diff --git a/.github/workflows/react_renderer.yml b/.github/workflows/react_renderer.yml index 0732db2ad..de111ccc4 100644 --- a/.github/workflows/react_renderer.yml +++ b/.github/workflows/react_renderer.yml @@ -58,6 +58,14 @@ jobs: - name: Test React renderer working-directory: ./renderers/react run: npm test + + - name: Build React Demo + working-directory: ./renderers/react + run: npm run build:demo + + - name: Test React Demo + working-directory: ./renderers/react + run: npm run test:demo lint: runs-on: ubuntu-latest diff --git a/.gitignore b/.gitignore index 879a4f263..822fbfab3 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,4 @@ a2a_agents/python/a2ui_agent/src/a2ui/assets/**/*.json agent_sdks/python/src/a2ui/assets/**/*.json ## Generated JS file from the strictly-typed `sandbox.ts`. samples/client/angular/projects/mcp_calculator/public/sandbox_iframe/sandbox.js +*.tsbuildinfo diff --git a/renderers/react/a2ui_explorer/README.md b/renderers/react/a2ui_explorer/README.md new file mode 100644 index 000000000..7db40651f --- /dev/null +++ b/renderers/react/a2ui_explorer/README.md @@ -0,0 +1,62 @@ +# A2UI React Gallery App + +This is the reference Gallery Application for the A2UI React renderer. It allows you to explore A2UI samples, inspect the live data model, and step through the message rendering process. + +## Prerequisites + +This application depends on the following local libraries in this repository: +1. `@a2ui/web_core` (located in `renderers/web_core`) +2. `@a2ui/react_prototype` (located in `renderers/react_prototype`) + +## Building Dependencies + +Before running the gallery app, you must build the local renderer library: + +```bash +# Navigate to the React renderer library +cd ../../../renderers/react_prototype + +# Install and build the library +npm install +npm run build +``` + +*Note: Ensure `@a2ui/web_core` is also built if you have made changes to the core logic.* + +## Setup and Development + +Once the dependencies are built, you can start the gallery app: + +```bash +# Navigate to this directory +cd samples/client/react + +# Install dependencies +npm install + +# Start the development server +npm run dev +``` + +## Building for Production + +To create a production build of the gallery app: + +```bash +npm run build +``` + +## Running Tests + +To run the integration tests: + +```bash +npm test +``` + +## Gallery Features + +- **3-Column Layout**: Left (Sample selection), Center (Live preview & Message stepper), Right (Data model & Action logs). +- **Progressive Stepper**: Use the "Advance" buttons next to each JSON message to see how the UI builds up incrementally. +- **Action Logs**: View real-time logs of actions triggered by user interactions. +- **Data Model Inspector**: Observe how the surface's data model changes as you interact with form fields. diff --git a/renderers/react/a2ui_explorer/eslint.config.js b/renderers/react/a2ui_explorer/eslint.config.js new file mode 100644 index 000000000..0842785dd --- /dev/null +++ b/renderers/react/a2ui_explorer/eslint.config.js @@ -0,0 +1,39 @@ +/** + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import js from '@eslint/js' +import globals from 'globals' +import reactHooks from 'eslint-plugin-react-hooks' +import reactRefresh from 'eslint-plugin-react-refresh' +import tseslint from 'typescript-eslint' +import { defineConfig, globalIgnores } from 'eslint/config' + +export default defineConfig([ + globalIgnores(['dist']), + { + files: ['**/*.{ts,tsx}'], + extends: [ + js.configs.recommended, + tseslint.configs.recommended, + reactHooks.configs.flat.recommended, + reactRefresh.configs.vite, + ], + languageOptions: { + ecmaVersion: 2020, + globals: globals.browser, + }, + }, +]) diff --git a/renderers/react/a2ui_explorer/index.html b/renderers/react/a2ui_explorer/index.html new file mode 100644 index 000000000..77fa01208 --- /dev/null +++ b/renderers/react/a2ui_explorer/index.html @@ -0,0 +1,30 @@ + + + + + + + + + + react + + +
+ + + diff --git a/renderers/react/a2ui_explorer/public/vite.svg b/renderers/react/a2ui_explorer/public/vite.svg new file mode 100644 index 000000000..e7b8dfb1b --- /dev/null +++ b/renderers/react/a2ui_explorer/public/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/renderers/react/a2ui_explorer/src/App.css b/renderers/react/a2ui_explorer/src/App.css new file mode 100644 index 000000000..5c31aced7 --- /dev/null +++ b/renderers/react/a2ui_explorer/src/App.css @@ -0,0 +1,58 @@ +/** + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#root { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + text-align: center; +} + +.logo { + height: 6em; + padding: 1.5em; + will-change: filter; + transition: filter 300ms; +} +.logo:hover { + filter: drop-shadow(0 0 2em #646cffaa); +} +.logo.react:hover { + filter: drop-shadow(0 0 2em #61dafbaa); +} + +@keyframes logo-spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} + +@media (prefers-reduced-motion: no-preference) { + a:nth-of-type(2) .logo { + animation: logo-spin infinite 20s linear; + } +} + +.card { + padding: 2em; +} + +.read-the-docs { + color: #888; +} diff --git a/renderers/react/a2ui_explorer/src/App.tsx b/renderers/react/a2ui_explorer/src/App.tsx new file mode 100644 index 000000000..dc08e5551 --- /dev/null +++ b/renderers/react/a2ui_explorer/src/App.tsx @@ -0,0 +1,328 @@ +/** + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { useState, useEffect, useSyncExternalStore, useCallback } from 'react'; +import { MessageProcessor, SurfaceModel } from '@a2ui/web_core/v0_9'; +import { minimalCatalog, basicCatalog, A2uiSurface } from '@a2ui/react/v0_9'; + +// Import Minimal examples +import min1 from "../../../../specification/v0_9/json/catalogs/minimal/examples/1_simple_text.json"; +import min2 from "../../../../specification/v0_9/json/catalogs/minimal/examples/2_row_layout.json"; +import min3 from "../../../../specification/v0_9/json/catalogs/minimal/examples/3_interactive_button.json"; +import min4 from "../../../../specification/v0_9/json/catalogs/minimal/examples/4_login_form.json"; +import min5 from "../../../../specification/v0_9/json/catalogs/minimal/examples/5_complex_layout.json"; +import min6 from "../../../../specification/v0_9/json/catalogs/minimal/examples/6_capitalized_text.json"; +import min7 from "../../../../specification/v0_9/json/catalogs/minimal/examples/7_incremental.json"; + +// Import Basic examples +import b01 from "../../../../specification/v0_9/json/catalogs/basic/examples/01_flight-status.json"; +import b02 from "../../../../specification/v0_9/json/catalogs/basic/examples/02_email-compose.json"; +import b03 from "../../../../specification/v0_9/json/catalogs/basic/examples/03_calendar-day.json"; +import b04 from "../../../../specification/v0_9/json/catalogs/basic/examples/04_weather-current.json"; +import b05 from "../../../../specification/v0_9/json/catalogs/basic/examples/05_product-card.json"; +import b06 from "../../../../specification/v0_9/json/catalogs/basic/examples/06_music-player.json"; +import b07 from "../../../../specification/v0_9/json/catalogs/basic/examples/07_task-card.json"; +import b08 from "../../../../specification/v0_9/json/catalogs/basic/examples/08_user-profile.json"; +import b09 from "../../../../specification/v0_9/json/catalogs/basic/examples/09_login-form.json"; +import b10 from "../../../../specification/v0_9/json/catalogs/basic/examples/10_notification-permission.json"; +import b11 from "../../../../specification/v0_9/json/catalogs/basic/examples/11_purchase-complete.json"; +import b12 from "../../../../specification/v0_9/json/catalogs/basic/examples/12_chat-message.json"; +import b13 from "../../../../specification/v0_9/json/catalogs/basic/examples/13_coffee-order.json"; +import b14 from "../../../../specification/v0_9/json/catalogs/basic/examples/14_sports-player.json"; +import b15 from "../../../../specification/v0_9/json/catalogs/basic/examples/15_account-balance.json"; +import b16 from "../../../../specification/v0_9/json/catalogs/basic/examples/16_workout-summary.json"; +import b17 from "../../../../specification/v0_9/json/catalogs/basic/examples/17_event-detail.json"; +import b18 from "../../../../specification/v0_9/json/catalogs/basic/examples/18_track-list.json"; +import b19 from "../../../../specification/v0_9/json/catalogs/basic/examples/19_software-purchase.json"; +import b20 from "../../../../specification/v0_9/json/catalogs/basic/examples/20_restaurant-card.json"; +import b21 from "../../../../specification/v0_9/json/catalogs/basic/examples/21_shipping-status.json"; +import b22 from "../../../../specification/v0_9/json/catalogs/basic/examples/22_credit-card.json"; +import b23 from "../../../../specification/v0_9/json/catalogs/basic/examples/23_step-counter.json"; +import b24 from "../../../../specification/v0_9/json/catalogs/basic/examples/24_recipe-card.json"; +import b25 from "../../../../specification/v0_9/json/catalogs/basic/examples/25_contact-card.json"; +import b26 from "../../../../specification/v0_9/json/catalogs/basic/examples/26_podcast-episode.json"; +import b27 from "../../../../specification/v0_9/json/catalogs/basic/examples/27_stats-card.json"; +import b28 from "../../../../specification/v0_9/json/catalogs/basic/examples/28_countdown-timer.json"; +import b29 from "../../../../specification/v0_9/json/catalogs/basic/examples/29_movie-card.json"; + +const exampleFiles = [ + { key: 'min1', data: min1, catalog: 'Minimal' }, + { key: 'min2', data: min2, catalog: 'Minimal' }, + { key: 'min3', data: min3, catalog: 'Minimal' }, + { key: 'min4', data: min4, catalog: 'Minimal' }, + { key: 'min5', data: min5, catalog: 'Minimal' }, + { key: 'min6', data: min6, catalog: 'Minimal' }, + { key: 'min7', data: min7, catalog: 'Minimal' }, + { key: 'b01', data: b01, catalog: 'Basic' }, + { key: 'b02', data: b02, catalog: 'Basic' }, + { key: 'b03', data: b03, catalog: 'Basic' }, + { key: 'b04', data: b04, catalog: 'Basic' }, + { key: 'b05', data: b05, catalog: 'Basic' }, + { key: 'b06', data: b06, catalog: 'Basic' }, + { key: 'b07', data: b07, catalog: 'Basic' }, + { key: 'b08', data: b08, catalog: 'Basic' }, + { key: 'b09', data: b09, catalog: 'Basic' }, + { key: 'b10', data: b10, catalog: 'Basic' }, + { key: 'b11', data: b11, catalog: 'Basic' }, + { key: 'b12', data: b12, catalog: 'Basic' }, + { key: 'b13', data: b13, catalog: 'Basic' }, + { key: 'b14', data: b14, catalog: 'Basic' }, + { key: 'b15', data: b15, catalog: 'Basic' }, + { key: 'b16', data: b16, catalog: 'Basic' }, + { key: 'b17', data: b17, catalog: 'Basic' }, + { key: 'b18', data: b18, catalog: 'Basic' }, + { key: 'b19', data: b19, catalog: 'Basic' }, + { key: 'b20', data: b20, catalog: 'Basic' }, + { key: 'b21', data: b21, catalog: 'Basic' }, + { key: 'b22', data: b22, catalog: 'Basic' }, + { key: 'b23', data: b23, catalog: 'Basic' }, + { key: 'b24', data: b24, catalog: 'Basic' }, + { key: 'b25', data: b25, catalog: 'Basic' }, + { key: 'b26', data: b26, catalog: 'Basic' }, + { key: 'b27', data: b27, catalog: 'Basic' }, + { key: 'b28', data: b28, catalog: 'Basic' }, + { key: 'b29', data: b29, catalog: 'Basic' }, +]; + +const getMessages = (ex: any) => Array.isArray(ex) ? ex : ex?.messages; + +const DataModelViewer = ({ surface }: { surface: SurfaceModel }) => { + const subscribeHook = useCallback((callback: () => void) => { + const bound = surface.dataModel.subscribe('/', callback); + return () => bound.unsubscribe(); + }, [surface]); + + const getSnapshot = useCallback(() => { + return JSON.stringify(surface.dataModel.get('/'), null, 2); + }, [surface]); + + const dataString = useSyncExternalStore(subscribeHook, getSnapshot); + + return ( +
+ Surface: {surface.id} +
+        {dataString}
+      
+
+ ); +}; + +export default function App() { + const [selectedExampleKey, setSelectedExampleKey] = useState(exampleFiles[0].key); + const selectedExample = exampleFiles.find((e) => e.key === selectedExampleKey)?.data as any; + + const [logs, setLogs] = useState([]); + const [processor, setProcessor] = useState | null>(null); + const [surfaces, setSurfaces] = useState([]); + const [currentMessageIndex, setCurrentMessageIndex] = useState(-1); + + // Initialize or reset processor + const resetProcessor = useCallback((advanceToEnd: boolean = false) => { + setProcessor(prevProcessor => { + if (prevProcessor) { + prevProcessor.model.dispose(); + } + const newProcessor = new MessageProcessor([minimalCatalog as any, basicCatalog as any], async (action: any) => { + setLogs((l) => [...l, { time: new Date().toLocaleTimeString(), action }]); + }); + + const msgs = getMessages(selectedExample); + if (advanceToEnd && msgs) { + newProcessor.processMessages(msgs); + } + return newProcessor; + }); + + setLogs([]); + setSurfaces([]); + + const msgs = getMessages(selectedExample); + if (advanceToEnd && msgs) { + setCurrentMessageIndex(msgs.length - 1); + } else { + setCurrentMessageIndex(-1); + } + }, [selectedExample]); + + // Effect to handle example selection change + useEffect(() => { + resetProcessor(true); + // Cleanup on unmount or when changing examples + return () => { + setProcessor(prev => { + if (prev) prev.model.dispose(); + return null; + }); + }; + }, [selectedExampleKey, resetProcessor]); + + // Handle surface subscriptions + useEffect(() => { + if (!processor) { + setSurfaces([]); + return; + } + + const updateSurfaces = () => { + setSurfaces(Array.from(processor.model.surfacesMap.values()).map((s: any) => s.id as string)); + }; + + updateSurfaces(); + + const unsub1 = processor.model.onSurfaceCreated.subscribe(updateSurfaces); + const unsub2 = processor.model.onSurfaceDeleted.subscribe(updateSurfaces); + + return () => { + unsub1.unsubscribe(); + unsub2.unsubscribe(); + }; + }, [processor]); + + const advanceToMessage = (index: number) => { + const msgs = getMessages(selectedExample); + if (!processor || !msgs) return; + + // Process messages from currentMessageIndex + 1 to index + const messagesToProcess = msgs.slice(currentMessageIndex + 1, index + 1); + if (messagesToProcess.length > 0) { + processor.processMessages(messagesToProcess); + setCurrentMessageIndex(index); + } + }; + + const handleReset = () => { + resetProcessor(false); + }; + + const messages = getMessages(selectedExample) || []; + + return ( +
+ + {/* Left Column: Sample List */} +
+

Samples

+
    + {exampleFiles.map((ex) => ( +
  • + +
  • + ))} +
+
+ + {/* Center Column: Preview & JSON Stepper */} +
+
+

Preview

+ {surfaces.length === 0 &&

No surfaces loaded. Advance the stepper to create one.

} + {surfaces.map((surfaceId) => { + const surface = processor?.model.getSurface(surfaceId); + if (!surface) return null; + return ( +
+
+ +
+
+ ); + })} +
+ +
+
+

Messages

+ +
+ +
+ {messages.map((msg: any, i: number) => { + const isActive = i <= currentMessageIndex; + return ( +
+
+ Message {i + 1} + {!isActive && ( + + )} +
+
+                    {JSON.stringify(msg, null, 2)}
+                  
+
+ ); + })} +
+
+
+ + {/* Right Column: Live DataModelViewer & Action Logs */} +
+
+

Data Model

+
+ {surfaces.length === 0 ?

Empty Data Model

: null} + {surfaces.map((surfaceId) => { + const surface = processor?.model.getSurface(surfaceId); + if (!surface) return null; + return ; + })} +
+
+ +
+

Action Logs

+
+ {logs.length === 0 ?

No actions logged yet.

: null} + {logs.map((log, i) => ( +
+ {log.time} +
{JSON.stringify(log.action, null, 2)}
+
+ ))} +
+
+
+ +
+ ); +} diff --git a/renderers/react/a2ui_explorer/src/assets/react.svg b/renderers/react/a2ui_explorer/src/assets/react.svg new file mode 100644 index 000000000..6c87de9bb --- /dev/null +++ b/renderers/react/a2ui_explorer/src/assets/react.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/renderers/react/a2ui_explorer/src/index.css b/renderers/react/a2ui_explorer/src/index.css new file mode 100644 index 000000000..f1e01cfe6 --- /dev/null +++ b/renderers/react/a2ui_explorer/src/index.css @@ -0,0 +1,84 @@ +/** + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +:root { + font-family: system-ui, Avenir, Helvetica, Arial, sans-serif; + line-height: 1.5; + font-weight: 400; + + color-scheme: light dark; + color: rgba(255, 255, 255, 0.87); + background-color: #242424; + + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +a { + font-weight: 500; + color: #646cff; + text-decoration: inherit; +} +a:hover { + color: #535bf2; +} + +body { + margin: 0; + display: flex; + place-items: center; + min-width: 320px; + min-height: 100vh; +} + +h1 { + font-size: 3.2em; + line-height: 1.1; +} + +button { + border-radius: 8px; + border: 1px solid transparent; + padding: 0.6em 1.2em; + font-size: 1em; + font-weight: 500; + font-family: inherit; + background-color: #1a1a1a; + cursor: pointer; + transition: border-color 0.25s; +} +button:hover { + border-color: #646cff; +} +button:focus, +button:focus-visible { + outline: 4px auto -webkit-focus-ring-color; +} + +@media (prefers-color-scheme: light) { + :root { + color: #213547; + background-color: #ffffff; + } + a:hover { + color: #747bff; + } + button { + background-color: #f9f9f9; + } +} diff --git a/renderers/react/a2ui_explorer/src/integration.test.tsx b/renderers/react/a2ui_explorer/src/integration.test.tsx new file mode 100644 index 000000000..e93ab0ca1 --- /dev/null +++ b/renderers/react/a2ui_explorer/src/integration.test.tsx @@ -0,0 +1,84 @@ +/** + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { describe, it, expect } from 'vitest'; +import { render, screen, act, fireEvent } from '@testing-library/react'; +import React from 'react'; +import { MessageProcessor } from '@a2ui/web_core/v0_9'; +import { A2uiSurface, minimalCatalog } from '@a2ui/react/v0_9'; + +import ex1 from "../../../../specification/v0_9/json/catalogs/minimal/examples/1_simple_text.json"; +import ex2 from "../../../../specification/v0_9/json/catalogs/minimal/examples/2_row_layout.json"; +import ex4 from "../../../../specification/v0_9/json/catalogs/minimal/examples/4_login_form.json"; + +describe('Gallery Integration Tests', () => { + it('renders Simple Text -> "Hello Minimal Catalog"', async () => { + const processor = new MessageProcessor([minimalCatalog as any], async () => {}); + processor.processMessages(ex1.messages as any[]); + + const surface = processor.model.getSurface("example_1"); + expect(surface).toBeDefined(); + + render( + + + + ); + + expect(screen.getByText('Hello, Minimal Catalog!')).toBeInTheDocument(); + }); + + it('renders Row layout -> content visibility', async () => { + const processor = new MessageProcessor([minimalCatalog as any], async () => {}); + processor.processMessages(ex2.messages as any[]); + + const surface = processor.model.getSurface("example_2"); + expect(surface).toBeDefined(); + + render( + + + + ); + + expect(screen.getByText('Left Content')).toBeInTheDocument(); + expect(screen.getByText('Right Content')).toBeInTheDocument(); + }); + + it('handles Login form -> input updates data model', async () => { + const processor = new MessageProcessor([minimalCatalog as any], async () => {}); + processor.processMessages(ex4.messages as any[]); + + const surface = processor.model.getSurface("example_4"); + expect(surface).toBeDefined(); + + render( + + + + ); + + const usernameInput = screen.getByLabelText('Username') as HTMLInputElement; + expect(usernameInput).toBeDefined(); + + await act(async () => { + fireEvent.change(usernameInput, { target: { value: 'alice' } }); + }); + + expect(surface!.dataModel.get('/username')).toBe('alice'); + }); +}); + diff --git a/renderers/react/a2ui_explorer/src/main.tsx b/renderers/react/a2ui_explorer/src/main.tsx new file mode 100644 index 000000000..4380b3cb3 --- /dev/null +++ b/renderers/react/a2ui_explorer/src/main.tsx @@ -0,0 +1,26 @@ +/** + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { StrictMode } from 'react' +import { createRoot } from 'react-dom/client' +import './index.css' +import App from './App.tsx' + +createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/renderers/react/a2ui_explorer/src/setupTests.ts b/renderers/react/a2ui_explorer/src/setupTests.ts new file mode 100644 index 000000000..5816a5872 --- /dev/null +++ b/renderers/react/a2ui_explorer/src/setupTests.ts @@ -0,0 +1,17 @@ +/** + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import '@testing-library/jest-dom'; diff --git a/renderers/react/a2ui_explorer/tsconfig.app.json b/renderers/react/a2ui_explorer/tsconfig.app.json new file mode 100644 index 000000000..d57468003 --- /dev/null +++ b/renderers/react/a2ui_explorer/tsconfig.app.json @@ -0,0 +1,31 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "types": ["vite/client"], + "skipLibCheck": true, + + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + "resolveJsonModule": true, + + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true, + "paths": { + "@a2ui/react": ["../src/index.ts"], + "@a2ui/react/*": ["../src/*"] + } + }, + "include": ["src"] +} diff --git a/renderers/react/a2ui_explorer/tsconfig.json b/renderers/react/a2ui_explorer/tsconfig.json new file mode 100644 index 000000000..1ffef600d --- /dev/null +++ b/renderers/react/a2ui_explorer/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/renderers/react/a2ui_explorer/tsconfig.node.json b/renderers/react/a2ui_explorer/tsconfig.node.json new file mode 100644 index 000000000..8a67f62f4 --- /dev/null +++ b/renderers/react/a2ui_explorer/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/renderers/react/a2ui_explorer/vite.config.ts b/renderers/react/a2ui_explorer/vite.config.ts new file mode 100644 index 000000000..e0ba24985 --- /dev/null +++ b/renderers/react/a2ui_explorer/vite.config.ts @@ -0,0 +1,38 @@ +/** + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' + +import { resolve } from 'path' + +// https://vite.dev/config/ +export default defineConfig({ + plugins: [react()], + resolve: { + alias: { + '@a2ui/react/v0_9': resolve(__dirname, '../src/v0_9/index.ts'), + '@a2ui/react/v0_8': resolve(__dirname, '../src/v0_8/index.ts'), + '@a2ui/react/styles': resolve(__dirname, '../src/styles/index.ts'), + '@a2ui/react': resolve(__dirname, '../src/index.ts') + } + }, + test: { + environment: 'jsdom', + globals: true, + setupFiles: ['./src/setupTests.ts'] + } +} as any) diff --git a/renderers/react/package-lock.json b/renderers/react/package-lock.json index 84d00d668..8ad0f6a90 100644 --- a/renderers/react/package-lock.json +++ b/renderers/react/package-lock.json @@ -11,27 +11,36 @@ "dependencies": { "@a2ui/web_core": "file:../web_core", "clsx": "^2.1.0", - "markdown-it": "^14.0.0" + "markdown-it": "^14.0.0", + "rxjs": "^7.8.1", + "zod": "^3.23.8" }, "devDependencies": { "@eslint/js": "^9.0.0", "@testing-library/jest-dom": "^6.6.0", "@testing-library/react": "^16.0.0", "@types/markdown-it": "^14.1.0", + "@types/node": "^24.10.1", "@types/react": "^18.3.0", "@types/react-dom": "^18.3.0", + "@vitejs/plugin-react": "^5.1.1", "eslint": "^9.0.0", "eslint-config-prettier": "^10.0.0", "eslint-plugin-react": "^7.37.0", "eslint-plugin-react-hooks": "^5.0.0", + "eslint-plugin-react-refresh": "^0.4.24", + "globals": "^16.5.0", "gts": "^7.0.0", "jsdom": "^28.0.0", "prettier": "^3.4.0", + "puppeteer": "^24.39.0", "react": "^18.3.0", "react-dom": "^18.3.0", "tsup": "^8.0.0", + "tsx": "^4.21.0", "typescript": "^5.8.0", "typescript-eslint": "^8.0.0", + "vite": "^7.3.1", "vitest": "^4.0.18" }, "engines": { @@ -127,8 +136,9 @@ "license": "MIT" }, "node_modules/@babel/code-frame": { - "version": "7.28.6", - "integrity": "sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", "dev": true, "license": "MIT", "dependencies": { @@ -140,6 +150,160 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/compat-data": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", + "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", + "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helpers": "^7.28.6", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", + "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.28.6", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", + "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-validator-identifier": { "version": "7.28.5", "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", @@ -149,6 +313,78 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.2.tgz", + "integrity": "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", + "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", + "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", + "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/runtime": { "version": "7.28.6", "integrity": "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==", @@ -158,6 +394,54 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/template": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@csstools/color-helpers": { "version": "5.1.0", "integrity": "sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==", @@ -800,6 +1084,19 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@eslint/js": { "version": "9.39.2", "integrity": "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==", @@ -909,6 +1206,17 @@ "@jridgewell/trace-mapping": "^0.3.24" } }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.2", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", @@ -946,6 +1254,48 @@ "url": "https://opencollective.com/pkgr" } }, + "node_modules/@puppeteer/browsers": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.13.0.tgz", + "integrity": "sha512-46BZJYJjc/WwmKjsvDFykHtXrtomsCIrwYQPOP7VfMJoZY2bsDF9oROBABR3paDjDcmkUye1Pb1BqdcdiipaWA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "debug": "^4.4.3", + "extract-zip": "^2.0.1", + "progress": "^2.0.3", + "proxy-agent": "^6.5.0", + "semver": "^7.7.4", + "tar-fs": "^3.1.1", + "yargs": "^17.7.2" + }, + "bin": { + "browsers": "lib/cjs/main-cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@puppeteer/browsers/node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.3.tgz", + "integrity": "sha512-eybk3TjzzzV97Dlj5c+XrBFW57eTNhzod66y9HrBlzJ6NsCrWCp/2kaPS3K9wJmurBC0Tdw4yPjXKZqlznim3Q==", + "dev": true, + "license": "MIT" + }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.57.1", "integrity": "sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg==", @@ -1349,6 +1699,13 @@ } } }, + "node_modules/@tootallnate/quickjs-emscripten": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", + "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/aria-query": { "version": "5.0.4", "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", @@ -1356,6 +1713,51 @@ "license": "MIT", "peer": true }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, "node_modules/@types/chai": { "version": "5.2.3", "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", @@ -1412,6 +1814,16 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/node": { + "version": "24.12.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.12.0.tgz", + "integrity": "sha512-GYDxsZi3ChgmckRT9HPU0WEhKLP08ev/Yfcq2AstjrDASOYCSXeyjDsHg4v5t4jOj7cyDX3vmprafKlWIG9MXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.16.0" + } + }, "node_modules/@types/normalize-package-data": { "version": "2.4.4", "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", @@ -1443,6 +1855,17 @@ "@types/react": "^18.0.0" } }, + "node_modules/@types/yauzl": { + "version": "2.10.3", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", + "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "8.54.0", "integrity": "sha512-hAAP5io/7csFStuOmR782YmTthKBJ9ND3WVL60hcOjvtGFb+HJxH4O5huAcmcZ9v9G8P+JETiZ/G1B8MALnWZQ==", @@ -1698,6 +2121,27 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@vitejs/plugin-react": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.2.0.tgz", + "integrity": "sha512-YmKkfhOAi3wsB1PhJq5Scj3GXMn3WvtQ/JC0xoopuHoXSdmtdStOpFrYaT1kie2YgFBcIe64ROzMYRjCrYOdYw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.29.0", + "@babel/plugin-transform-react-jsx-self": "^7.27.1", + "@babel/plugin-transform-react-jsx-source": "^7.27.1", + "@rolldown/pluginutils": "1.0.0-rc.3", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.18.0" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, "node_modules/@vitest/expect": { "version": "4.0.18", "integrity": "sha512-8sCWUyckXXYvx4opfzVY03EOiYVxyNrHS5QxX3DAIi5dpJAAkyJezHCP77VMX4HKA2LDT/Jpfo8i2r5BE3GnQQ==", @@ -2054,6 +2498,19 @@ "node": ">=12" } }, + "node_modules/ast-types": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", + "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/async-function": { "version": "1.0.0", "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", @@ -2084,13 +2541,129 @@ "dev": true, "license": "MIT" }, - "node_modules/bidi-js": { - "version": "1.0.3", - "integrity": "sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==", + "node_modules/bare-events": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.8.2.tgz", + "integrity": "sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ==", "dev": true, - "license": "MIT", - "dependencies": { - "require-from-string": "^2.0.2" + "license": "Apache-2.0", + "peerDependencies": { + "bare-abort-controller": "*" + }, + "peerDependenciesMeta": { + "bare-abort-controller": { + "optional": true + } + } + }, + "node_modules/bare-fs": { + "version": "4.5.6", + "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.5.6.tgz", + "integrity": "sha512-1QovqDrR80Pmt5HPAsMsXTCFcDYr+NSUKW6nd6WO5v0JBmnItc/irNRzm2KOQ5oZ69P37y+AMujNyNtG+1Rggw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bare-events": "^2.5.4", + "bare-path": "^3.0.0", + "bare-stream": "^2.6.4", + "bare-url": "^2.2.2", + "fast-fifo": "^1.3.2" + }, + "engines": { + "bare": ">=1.16.0" + }, + "peerDependencies": { + "bare-buffer": "*" + }, + "peerDependenciesMeta": { + "bare-buffer": { + "optional": true + } + } + }, + "node_modules/bare-os": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.8.0.tgz", + "integrity": "sha512-Dc9/SlwfxkXIGYhvMQNUtKaXCaGkZYGcd1vuNUUADVqzu4/vQfvnMkYYOUnt2VwQ2AqKr/8qAVFRtwETljgeFg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "bare": ">=1.14.0" + } + }, + "node_modules/bare-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-3.0.0.tgz", + "integrity": "sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bare-os": "^3.0.1" + } + }, + "node_modules/bare-stream": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.10.0.tgz", + "integrity": "sha512-DOPZF/DDcDruKDA43cOw6e9Quq5daua7ygcAwJE/pKJsRWhgSSemi7qVNGE5kyDIxIeN1533G/zfbvWX7Wcb9w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "streamx": "^2.25.0", + "teex": "^1.0.1" + }, + "peerDependencies": { + "bare-buffer": "*", + "bare-events": "*" + }, + "peerDependenciesMeta": { + "bare-buffer": { + "optional": true + }, + "bare-events": { + "optional": true + } + } + }, + "node_modules/bare-url": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.4.0.tgz", + "integrity": "sha512-NSTU5WN+fy/L0DDenfE8SXQna4voXuW0FHM7wH8i3/q9khUSchfPbPezO4zSFMnDGIf9YE+mt/RWhZgNRKRIXA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bare-path": "^3.0.0" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.9", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.9.tgz", + "integrity": "sha512-OZd0e2mU11ClX8+IdXe3r0dbqMEznRiT4TfbhYIbcRPZkqJ7Qwer8ij3GZAmLsRKa+II9V1v5czCkvmHH3XZBg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/basic-ftp": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.2.0.tgz", + "integrity": "sha512-VoMINM2rqJwJgfdHq6RiUudKt2BV+FY5ZFezP/ypmwayk68+NzzAQy4XXLlqsGD4MCzq3DrmNFD/uUmBJuGoXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/bidi-js": { + "version": "1.0.3", + "integrity": "sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==", + "dev": true, + "license": "MIT", + "dependencies": { + "require-from-string": "^2.0.2" } }, "node_modules/brace-expansion": { @@ -2103,6 +2676,50 @@ "concat-map": "0.0.1" } }, + "node_modules/browserslist": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, "node_modules/bundle-require": { "version": "5.1.0", "integrity": "sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==", @@ -2209,6 +2826,27 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/caniuse-lite": { + "version": "1.0.30001780", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001780.tgz", + "integrity": "sha512-llngX0E7nQci5BPJDqoZSbuZ5Bcs9F5db7EtgfwBerX9XGtkkiO4NwfDDIRzHTTwcYC8vC7bmeUEPGrKlR/TkQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, "node_modules/chai": { "version": "6.2.2", "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", @@ -2270,6 +2908,20 @@ "url": "https://paulmillr.com/funding/" } }, + "node_modules/chromium-bidi": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-14.0.0.tgz", + "integrity": "sha512-9gYlLtS6tStdRWzrtXaTMnqcM4dudNegMXJxkR0I/CXObHalYeYcAMPrL19eroNZHtJ8DQmu1E+ZNOYu/IXMXw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "mitt": "^3.0.1", + "zod": "^3.24.1" + }, + "peerDependencies": { + "devtools-protocol": "*" + } + }, "node_modules/cli-cursor": { "version": "3.1.0", "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", @@ -2291,6 +2943,21 @@ "node": ">= 10" } }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/clsx": { "version": "2.1.1", "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", @@ -2347,6 +3014,40 @@ "node": "^14.18.0 || >=16.10.0" } }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cosmiconfig": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.1.tgz", + "integrity": "sha512-hr4ihw+DBqcvrsEDioRO31Z17x71pUYoNe/4h6Z0wB72p7MU7/9gH8Q3s12NFhHPfYBBOV3qyfUxmr/Yn3shnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "node_modules/cross-spawn": { "version": "7.0.6", "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", @@ -2401,6 +3102,16 @@ "dev": true, "license": "MIT" }, + "node_modules/data-uri-to-buffer": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz", + "integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, "node_modules/data-urls": { "version": "7.0.0", "integrity": "sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA==", @@ -2562,6 +3273,21 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/degenerator": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz", + "integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ast-types": "^0.13.4", + "escodegen": "^2.1.0", + "esprima": "^4.0.1" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/dequal": { "version": "2.0.3", "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", @@ -2571,6 +3297,13 @@ "node": ">=6" } }, + "node_modules/devtools-protocol": { + "version": "0.0.1581282", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1581282.tgz", + "integrity": "sha512-nv7iKtNZQshSW2hKzYNr46nM/Cfh5SEvE2oV0/SEGgc9XupIY5ggf84Cz8eJIkBce7S3bmTAauFD6aysMpnqsQ==", + "dev": true, + "license": "BSD-3-Clause" + }, "node_modules/doctrine": { "version": "2.1.0", "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", @@ -2604,12 +3337,29 @@ "node": ">= 0.4" } }, + "node_modules/electron-to-chromium": { + "version": "1.5.321", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.321.tgz", + "integrity": "sha512-L2C7Q279W2D/J4PLZLk7sebOILDSWos7bMsMNN06rK482umHUrh/3lM8G7IlHFOYip2oAg5nha1rCMxr/rs6ZQ==", + "dev": true, + "license": "ISC" + }, "node_modules/emoji-regex": { "version": "8.0.0", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true, "license": "MIT" }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, "node_modules/enhanced-resolve": { "version": "5.20.0", "integrity": "sha512-/ce7+jQ1PQ6rVXwe+jKEg5hW5ciicHwIQUagZkp6IufBoY3YDgdTTY1azVs0qoRgVmvsNB+rbjLJxDAeHHtwsQ==", @@ -2634,6 +3384,16 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/error-ex": { "version": "1.3.4", "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", @@ -2859,6 +3619,16 @@ "@esbuild/win32-x64": "0.27.2" } }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/escape-string-regexp": { "version": "4.0.0", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", @@ -2871,6 +3641,39 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/escodegen": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/escodegen/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/eslint": { "version": "9.39.2", "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", @@ -3117,6 +3920,16 @@ "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" } }, + "node_modules/eslint-plugin-react-refresh": { + "version": "0.4.26", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.26.tgz", + "integrity": "sha512-1RETEylht2O6FM/MvgnyvT+8K21wLqDNg4qD51Zj3guhjt433XbnnkVttHMyaVyAFD03QSV4LPS5iE3VQmO7XQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "eslint": ">=8.40" + } + }, "node_modules/eslint-scope": { "version": "8.4.0", "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", @@ -3162,6 +3975,20 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/esquery": { "version": "1.7.0", "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", @@ -3213,6 +4040,16 @@ "node": ">=0.10.0" } }, + "node_modules/events-universal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/events-universal/-/events-universal-1.0.1.tgz", + "integrity": "sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bare-events": "^2.7.0" + } + }, "node_modules/execa": { "version": "5.1.1", "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", @@ -3259,6 +4096,43 @@ "node": ">=4" } }, + "node_modules/extract-zip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + }, + "bin": { + "extract-zip": "cli.js" + }, + "engines": { + "node": ">= 10.17.0" + }, + "optionalDependencies": { + "@types/yauzl": "^2.9.1" + } + }, + "node_modules/extract-zip/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", @@ -3271,6 +4145,13 @@ "dev": true, "license": "Apache-2.0" }, + "node_modules/fast-fifo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", + "dev": true, + "license": "MIT" + }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", @@ -3283,6 +4164,16 @@ "dev": true, "license": "MIT" }, + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "pend": "~1.2.0" + } + }, "node_modules/fdir": { "version": "6.5.0", "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", @@ -3458,6 +4349,26 @@ "node": ">= 0.4" } }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, "node_modules/get-intrinsic": { "version": "1.3.0", "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", @@ -3536,6 +4447,21 @@ "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" } }, + "node_modules/get-uri": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.5.tgz", + "integrity": "sha512-b1O07XYq8eRuVzBNgJLstU6FYc1tS6wnMtF1I1D9lE8LxZSOGZ7LhxN54yPP6mGw5f2CkXY2BQUL9Fx41qvcIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "basic-ftp": "^5.0.2", + "data-uri-to-buffer": "^6.0.2", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/glob-parent": { "version": "6.0.2", "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", @@ -3549,8 +4475,9 @@ } }, "node_modules/globals": { - "version": "14.0.0", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "version": "16.5.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.5.0.tgz", + "integrity": "sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==", "dev": true, "license": "MIT", "engines": { @@ -3888,6 +4815,26 @@ "node": ">=8.0.0" } }, + "node_modules/inquirer/node_modules/rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/inquirer/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true, + "license": "0BSD" + }, "node_modules/internal-slot": { "version": "1.1.0", "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", @@ -3902,6 +4849,16 @@ "node": ">= 0.4" } }, + "node_modules/ip-address": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.0.tgz", + "integrity": "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, "node_modules/is-array-buffer": { "version": "3.0.5", "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", @@ -4397,6 +5354,19 @@ } } }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/json-buffer": { "version": "3.0.1", "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", @@ -4717,6 +5687,13 @@ "node": ">= 6" } }, + "node_modules/mitt": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", + "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", + "dev": true, + "license": "MIT" + }, "node_modules/mlly": { "version": "1.8.0", "integrity": "sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==", @@ -4785,6 +5762,23 @@ "ncp": "bin/ncp" } }, + "node_modules/netmask": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", + "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/node-releases": { + "version": "2.0.36", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.36.tgz", + "integrity": "sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==", + "dev": true, + "license": "MIT" + }, "node_modules/normalize-package-data": { "version": "3.0.3", "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", @@ -4935,6 +5929,16 @@ ], "license": "MIT" }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, "node_modules/onetime": { "version": "5.1.2", "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", @@ -5032,6 +6036,40 @@ "node": ">=6" } }, + "node_modules/pac-proxy-agent": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.2.0.tgz", + "integrity": "sha512-TEB8ESquiLMc0lV8vcd5Ql/JAKAoyzHFXaStwjkzpOpC5Yv+pIzLfHvjTSdf3vpa2bMiUQrg9i6276yn8666aA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tootallnate/quickjs-emscripten": "^0.23.0", + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "get-uri": "^6.0.1", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.6", + "pac-resolver": "^7.0.1", + "socks-proxy-agent": "^8.0.5" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/pac-resolver": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz", + "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==", + "dev": true, + "license": "MIT", + "dependencies": { + "degenerator": "^5.0.0", + "netmask": "^2.0.2" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/parent-module": { "version": "1.0.1", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", @@ -5116,6 +6154,13 @@ "dev": true, "license": "MIT" }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "dev": true, + "license": "MIT" + }, "node_modules/picocolors": { "version": "1.1.1", "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", @@ -5281,26 +6326,84 @@ "react-is": "^17.0.1" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dev": true, + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/proxy-agent": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.5.0.tgz", + "integrity": "sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "http-proxy-agent": "^7.0.1", + "https-proxy-agent": "^7.0.6", + "lru-cache": "^7.14.1", + "pac-proxy-agent": "^7.1.0", + "proxy-from-env": "^1.1.0", + "socks-proxy-agent": "^8.0.5" + }, + "engines": { + "node": ">= 14" } }, - "node_modules/prop-types": { - "version": "15.8.1", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "node_modules/proxy-agent/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", "dev": true, - "license": "MIT", - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" + "license": "ISC", + "engines": { + "node": ">=12" } }, - "node_modules/prop-types/node_modules/react-is": { - "version": "16.13.1", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", "dev": true, "license": "MIT" }, + "node_modules/pump": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", + "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, "node_modules/punycode": { "version": "2.3.1", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", @@ -5318,6 +6421,47 @@ "node": ">=6" } }, + "node_modules/puppeteer": { + "version": "24.40.0", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-24.40.0.tgz", + "integrity": "sha512-IxQbDq93XHVVLWHrAkFP7F7iHvb9o0mgfsSIMlhHb+JM+JjM1V4v4MNSQfcRWJopx9dsNOr9adYv0U5fm9BJBQ==", + "dev": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@puppeteer/browsers": "2.13.0", + "chromium-bidi": "14.0.0", + "cosmiconfig": "^9.0.0", + "devtools-protocol": "0.0.1581282", + "puppeteer-core": "24.40.0", + "typed-query-selector": "^2.12.1" + }, + "bin": { + "puppeteer": "lib/cjs/puppeteer/node/cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/puppeteer-core": { + "version": "24.40.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-24.40.0.tgz", + "integrity": "sha512-MWL3XbUCfVgGR0gRsidzT6oKJT2QydPLhMITU6HoVWiiv4gkb6gJi3pcdAa8q4HwjBTbqISOWVP4aJiiyUJvag==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@puppeteer/browsers": "2.13.0", + "chromium-bidi": "14.0.0", + "debug": "^4.4.3", + "devtools-protocol": "0.0.1581282", + "typed-query-selector": "^2.12.1", + "webdriver-bidi-protocol": "0.4.1", + "ws": "^8.19.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/quick-lru": { "version": "4.0.1", "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", @@ -5359,6 +6503,16 @@ "license": "MIT", "peer": true }, + "node_modules/react-refresh": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.18.0.tgz", + "integrity": "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/read-pkg": { "version": "5.2.0", "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", @@ -5576,6 +6730,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/require-from-string": { "version": "2.0.2", "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", @@ -5687,15 +6851,12 @@ } }, "node_modules/rxjs": { - "version": "6.6.7", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", - "dev": true, + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", "license": "Apache-2.0", "dependencies": { - "tslib": "^1.9.0" - }, - "engines": { - "npm": ">=2.0.0" + "tslib": "^2.1.0" } }, "node_modules/safe-array-concat": { @@ -5937,6 +7098,47 @@ "dev": true, "license": "ISC" }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks": { + "version": "2.8.7", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.7.tgz", + "integrity": "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ip-address": "^10.0.1", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz", + "integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "socks": "^2.8.3" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/source-map": { "version": "0.7.6", "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", @@ -6012,6 +7214,18 @@ "node": ">= 0.4" } }, + "node_modules/streamx": { + "version": "2.25.0", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.25.0.tgz", + "integrity": "sha512-0nQuG6jf1w+wddNEEXCF4nTg3LtufWINB5eFEN+5TNZW7KWJp6x87+JFL43vaAUPyCfH1wID+mNVyW6OHtFamg==", + "dev": true, + "license": "MIT", + "dependencies": { + "events-universal": "^1.0.0", + "fast-fifo": "^1.3.2", + "text-decoder": "^1.1.0" + } + }, "node_modules/string-width": { "version": "4.2.3", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", @@ -6244,6 +7458,84 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/tar-fs": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.1.2.tgz", + "integrity": "sha512-QGxxTxxyleAdyM3kpFs14ymbYmNFrfY+pHj7Z8FgtbZ7w2//VAgLMac7sT6nRpIHjppXO2AwwEOg0bPFVRcmXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "pump": "^3.0.0", + "tar-stream": "^3.1.5" + }, + "optionalDependencies": { + "bare-fs": "^4.0.1", + "bare-path": "^3.0.0" + } + }, + "node_modules/tar-stream": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.8.tgz", + "integrity": "sha512-U6QpVRyCGHva435KoNWy9PRoi2IFYCgtEhq9nmrPPpbRacPs9IH4aJ3gbrFC8dPcXvdSZ4XXfXT5Fshbp2MtlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "b4a": "^1.6.4", + "bare-fs": "^4.5.5", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" + } + }, + "node_modules/tar-stream/node_modules/b4a": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.8.0.tgz", + "integrity": "sha512-qRuSmNSkGQaHwNbM7J78Wwy+ghLEYF1zNrSeMxj4Kgw6y33O3mXcQ6Ie9fRvfU/YnxWkOchPXbaLb73TkIsfdg==", + "dev": true, + "license": "Apache-2.0", + "peerDependencies": { + "react-native-b4a": "*" + }, + "peerDependenciesMeta": { + "react-native-b4a": { + "optional": true + } + } + }, + "node_modules/teex": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/teex/-/teex-1.0.1.tgz", + "integrity": "sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "streamx": "^2.12.5" + } + }, + "node_modules/text-decoder": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.7.tgz", + "integrity": "sha512-vlLytXkeP4xvEq2otHeJfSQIRyWxo/oZGEbXrtEEF9Hnmrdly59sUbzZ/QgyWuLYHctCHxFF4tRQZNQ9k60ExQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "b4a": "^1.6.4" + } + }, + "node_modules/text-decoder/node_modules/b4a": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.8.0.tgz", + "integrity": "sha512-qRuSmNSkGQaHwNbM7J78Wwy+ghLEYF1zNrSeMxj4Kgw6y33O3mXcQ6Ie9fRvfU/YnxWkOchPXbaLb73TkIsfdg==", + "dev": true, + "license": "Apache-2.0", + "peerDependencies": { + "react-native-b4a": "*" + }, + "peerDependenciesMeta": { + "react-native-b4a": { + "optional": true + } + } + }, "node_modules/thenify": { "version": "3.3.1", "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", @@ -6421,9 +7713,9 @@ "license": "Apache-2.0" }, "node_modules/tslib": { - "version": "1.14.1", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true, + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, "node_modules/tsup": { @@ -6478,6 +7770,26 @@ } } }, + "node_modules/tsx": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.27.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, "node_modules/type-check": { "version": "0.4.0", "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", @@ -6576,6 +7888,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/typed-query-selector": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/typed-query-selector/-/typed-query-selector-2.12.1.tgz", + "integrity": "sha512-uzR+FzI8qrUEIu96oaeBJmd9E7CFEiQ3goA5qCVgc4s5llSubcfGHq9yUstZx/k4s9dXHVKsE35YWoFyvEqEHA==", + "dev": true, + "license": "MIT" + }, "node_modules/typescript": { "version": "5.9.3", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", @@ -6650,6 +7969,44 @@ "node": ">=20.18.1" } }, + "node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "dev": true, + "license": "MIT" + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, "node_modules/uri-js": { "version": "4.4.1", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", @@ -6841,6 +8198,13 @@ "node": ">=18" } }, + "node_modules/webdriver-bidi-protocol": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/webdriver-bidi-protocol/-/webdriver-bidi-protocol-0.4.1.tgz", + "integrity": "sha512-ARrjNjtWRRs2w4Tk7nqrf2gBI0QXWuOmMCx2hU+1jUt6d00MjMxURrhxhGbrsoiZKJrhTSTzbIrc554iKI10qw==", + "dev": true, + "license": "Apache-2.0" + }, "node_modules/webidl-conversions": { "version": "8.0.1", "integrity": "sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==", @@ -6998,6 +8362,47 @@ "node": ">=0.10.0" } }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, "node_modules/write-file-atomic": { "version": "6.0.0", "integrity": "sha512-GmqrO8WJ1NuzJ2DrziEI2o57jKAVIQNf8a18W3nCYU3H7PNWqCCVTeH6/NQE93CIllIgQS98rrmVkYgTX9fFJQ==", @@ -7023,6 +8428,28 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/ws": { + "version": "8.19.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz", + "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/xml-name-validator": { "version": "5.0.0", "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", @@ -7038,12 +8465,41 @@ "dev": true, "license": "MIT" }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, "node_modules/yallist": { "version": "4.0.0", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true, "license": "ISC" }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/yargs-parser": { "version": "20.2.9", "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", @@ -7053,6 +8509,27 @@ "node": ">=10" } }, + "node_modules/yargs/node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", @@ -7064,6 +8541,15 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } } } } diff --git a/renderers/react/package.json b/renderers/react/package.json index b36dfa188..acb028873 100644 --- a/renderers/react/package.json +++ b/renderers/react/package.json @@ -27,6 +27,16 @@ "default": "./dist/v0_8/index.cjs" } }, + "./v0_9": { + "import": { + "types": "./dist/v0_9/index.d.ts", + "default": "./dist/v0_9/index.js" + }, + "require": { + "types": "./dist/v0_9/index.d.cts", + "default": "./dist/v0_9/index.cjs" + } + }, "./styles": { "import": { "types": "./dist/styles/index.d.ts", @@ -55,12 +65,17 @@ "lint:fix": "eslint src --fix", "format": "prettier --write \"src/**/*.{ts,tsx}\"", "format:check": "prettier --check \"src/**/*.{ts,tsx}\"", - "clean": "rm -rf dist" + "clean": "rm -rf dist", + "demo": "cd a2ui_explorer && vite", + "build:demo": "cd a2ui_explorer && tsc -b && vite build", + "test:demo": "cd a2ui_explorer && vitest run src" }, "dependencies": { "@a2ui/web_core": "file:../web_core", "clsx": "^2.1.0", - "markdown-it": "^14.0.0" + "markdown-it": "^14.0.0", + "zod": "^3.23.8", + "rxjs": "^7.8.1" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", @@ -71,20 +86,27 @@ "@testing-library/jest-dom": "^6.6.0", "@testing-library/react": "^16.0.0", "@types/markdown-it": "^14.1.0", + "@types/node": "^24.10.1", "@types/react": "^18.3.0", "@types/react-dom": "^18.3.0", + "@vitejs/plugin-react": "^5.1.1", "eslint": "^9.0.0", "eslint-config-prettier": "^10.0.0", "eslint-plugin-react": "^7.37.0", "eslint-plugin-react-hooks": "^5.0.0", + "eslint-plugin-react-refresh": "^0.4.24", + "globals": "^16.5.0", "gts": "^7.0.0", "jsdom": "^28.0.0", "prettier": "^3.4.0", + "puppeteer": "^24.39.0", "react": "^18.3.0", "react-dom": "^18.3.0", "tsup": "^8.0.0", + "tsx": "^4.21.0", "typescript": "^5.8.0", "typescript-eslint": "^8.0.0", + "vite": "^7.3.1", "vitest": "^4.0.18" }, "keywords": [ diff --git a/renderers/react/src/v0_9/A2uiSurface.tsx b/renderers/react/src/v0_9/A2uiSurface.tsx new file mode 100644 index 000000000..0988bcc25 --- /dev/null +++ b/renderers/react/src/v0_9/A2uiSurface.tsx @@ -0,0 +1,98 @@ +/** + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React, {useSyncExternalStore} from 'react'; +import {type SurfaceModel, ComponentContext} from '@a2ui/web_core/v0_9'; +import type {ReactComponentImplementation} from './adapter'; + +export const A2uiSurface: React.FC<{surface: SurfaceModel}> = ({ + surface, +}) => { + const store = React.useMemo(() => { + let version = 0; + return { + subscribe: (cb: () => void) => { + const unsub1 = surface.componentsModel.onCreated.subscribe(() => { + version++; + cb(); + }); + const unsub2 = surface.componentsModel.onDeleted.subscribe(() => { + version++; + cb(); + }); + return () => { + unsub1.unsubscribe(); + unsub2.unsubscribe(); + }; + }, + getSnapshot: () => version, + }; + }, [surface]); + + useSyncExternalStore(store.subscribe, store.getSnapshot); + + const renderComponent = (id: string, currentBasePath: string) => { + try { + const componentModel = surface.componentsModel.get(id); + if (!componentModel) { + return ( +
+ [Loading {id}...] +
+ ); + } + + const compImpl = surface.catalog.components.get(componentModel.type); + + if (!compImpl) { + return ( +
+ Unknown component: {componentModel.type} +
+ ); + } + + const ComponentToRender = compImpl.render; + const context = new ComponentContext(surface, id, currentBasePath); + + const buildChild = (childId: string, specificPath?: string) => { + return renderComponent(childId, specificPath || context.dataContext.path); + }; + + return ( + + ); + } catch (e: any) { + return ( +
+ Error rendering {id}: {e.message} +
+ ); + } + }; + + const hasRoot = surface.componentsModel.get('root') !== undefined; + + if (!hasRoot) { + return
Waiting for root component...
; + } + + return <>{renderComponent('root', '/')}; +}; diff --git a/renderers/react/src/v0_9/adapter.tsx b/renderers/react/src/v0_9/adapter.tsx new file mode 100644 index 000000000..5b2c31588 --- /dev/null +++ b/renderers/react/src/v0_9/adapter.tsx @@ -0,0 +1,96 @@ +/** + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React, {useRef, useSyncExternalStore, useCallback} from 'react'; +import {type z} from 'zod'; +import {type ComponentContext, GenericBinder} from '@a2ui/web_core/v0_9'; +import type {ComponentApi, ResolveA2uiProps} from '@a2ui/web_core/v0_9'; + +export interface ReactComponentImplementation extends ComponentApi { + /** The framework-specific rendering wrapper. */ + render: React.FC<{ + context: ComponentContext; + buildChild: (id: string, basePath?: string) => React.ReactNode; + }>; +} + +export type ReactA2uiComponentProps = { + props: T; + buildChild: (id: string, basePath?: string) => React.ReactNode; + context: ComponentContext; +}; + +// --- Component Factories --- + +/** + * Creates a React component implementation using the deep generic binder. + */ +export function createReactComponent( + api: {name: string; schema: Schema}, + RenderComponent: React.FC>>> +): ReactComponentImplementation { + type Props = ResolveA2uiProps>; + + const ReactWrapper: React.FC<{context: ComponentContext; buildChild: any}> = ({ + context, + buildChild, + }) => { + const bindingRef = useRef | null>(null); + + if (!bindingRef.current) { + bindingRef.current = new GenericBinder(context, api.schema); + } + const binding = bindingRef.current; + + const subscribe = useCallback( + (callback: () => void) => { + const sub = binding.subscribe(callback); + return () => sub.unsubscribe(); + }, + [binding] + ); + + const getSnapshot = useCallback(() => binding.snapshot, [binding]); + const props = useSyncExternalStore(subscribe, getSnapshot); + + return ( + + ); + }; + + return { + name: api.name, + schema: api.schema, + render: ReactWrapper, + }; +} + +/** + * Creates a React component implementation that manages its own context bindings (no generic binder). + */ +export function createBinderlessComponent( + api: ComponentApi, + RenderComponent: React.FC<{ + context: ComponentContext; + buildChild: (id: string, basePath?: string) => React.ReactNode; + }> +): ReactComponentImplementation { + return { + name: api.name, + schema: api.schema, + render: RenderComponent, + }; +} diff --git a/renderers/react/src/v0_9/catalog/basic/components/ReactAudioPlayer.tsx b/renderers/react/src/v0_9/catalog/basic/components/ReactAudioPlayer.tsx new file mode 100644 index 000000000..1f0ce3e40 --- /dev/null +++ b/renderers/react/src/v0_9/catalog/basic/components/ReactAudioPlayer.tsx @@ -0,0 +1,36 @@ +/** + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import {createReactComponent} from '../../../adapter'; +import {AudioPlayerApi} from '@a2ui/web_core/v0_9/basic_catalog'; +import {getBaseLeafStyle} from '../utils'; + +export const ReactAudioPlayer = createReactComponent(AudioPlayerApi, ({props}) => { + const style: React.CSSProperties = { + ...getBaseLeafStyle(), + width: '100%', + }; + + return ( +
+ {props.description && ( + {props.description} + )} +
+ ); +}); diff --git a/renderers/react/src/v0_9/catalog/basic/components/ReactButton.tsx b/renderers/react/src/v0_9/catalog/basic/components/ReactButton.tsx new file mode 100644 index 000000000..cd8e332e2 --- /dev/null +++ b/renderers/react/src/v0_9/catalog/basic/components/ReactButton.tsx @@ -0,0 +1,47 @@ +/** + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import {createReactComponent} from '../../../adapter'; +import {ButtonApi} from '@a2ui/web_core/v0_9/basic_catalog'; +import {LEAF_MARGIN} from '../utils'; + +export const ReactButton = createReactComponent(ButtonApi, ({props, buildChild}) => { + const style: React.CSSProperties = { + margin: LEAF_MARGIN, + padding: '8px 16px', + cursor: 'pointer', + border: props.variant === 'borderless' ? 'none' : '1px solid #ccc', + backgroundColor: + props.variant === 'primary' + ? 'var(--a2ui-primary-color, #007bff)' + : props.variant === 'borderless' + ? 'transparent' + : '#fff', + color: props.variant === 'primary' ? '#fff' : 'inherit', + borderRadius: '4px', + display: 'inline-flex', + alignItems: 'center', + justifyContent: 'center', + boxSizing: 'border-box', + }; + + return ( + + ); +}); diff --git a/renderers/react/src/v0_9/catalog/basic/components/ReactCard.tsx b/renderers/react/src/v0_9/catalog/basic/components/ReactCard.tsx new file mode 100644 index 000000000..a945f3213 --- /dev/null +++ b/renderers/react/src/v0_9/catalog/basic/components/ReactCard.tsx @@ -0,0 +1,31 @@ +/** + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import {createReactComponent} from '../../../adapter'; +import {CardApi} from '@a2ui/web_core/v0_9/basic_catalog'; +import {getBaseContainerStyle} from '../utils'; + +export const ReactCard = createReactComponent(CardApi, ({props, buildChild}) => { + const style: React.CSSProperties = { + ...getBaseContainerStyle(), + backgroundColor: '#fff', + boxShadow: '0 2px 4px rgba(0,0,0,0.1)', + width: '100%', + }; + + return
{props.child ? buildChild(props.child) : null}
; +}); diff --git a/renderers/react/src/v0_9/catalog/basic/components/ReactCheckBox.tsx b/renderers/react/src/v0_9/catalog/basic/components/ReactCheckBox.tsx new file mode 100644 index 000000000..6410f70d2 --- /dev/null +++ b/renderers/react/src/v0_9/catalog/basic/components/ReactCheckBox.tsx @@ -0,0 +1,57 @@ +/** + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import {createReactComponent} from '../../../adapter'; +import {CheckBoxApi} from '@a2ui/web_core/v0_9/basic_catalog'; +import {LEAF_MARGIN} from '../utils'; + +export const ReactCheckBox = createReactComponent(CheckBoxApi, ({props}) => { + const onChange = (e: React.ChangeEvent) => { + props.setValue(e.target.checked); + }; + + const uniqueId = React.useId(); + + const hasError = props.validationErrors && props.validationErrors.length > 0; + + return ( +
+
+ + {props.label && ( + + )} +
+ {hasError && ( + + {props.validationErrors![0]} + + )} +
+ ); +}); diff --git a/renderers/react/src/v0_9/catalog/basic/components/ReactChildList.tsx b/renderers/react/src/v0_9/catalog/basic/components/ReactChildList.tsx new file mode 100644 index 000000000..a331304c4 --- /dev/null +++ b/renderers/react/src/v0_9/catalog/basic/components/ReactChildList.tsx @@ -0,0 +1,48 @@ +/** + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import {type ComponentContext} from '@a2ui/web_core/v0_9'; + +export const ReactChildList: React.FC<{ + childList: any; + context: ComponentContext; + buildChild: (id: string, basePath?: string) => React.ReactNode; +}> = ({childList, buildChild}) => { + if (Array.isArray(childList)) { + return ( + <> + {childList.map((item: any, i: number) => { + // The new binder outputs objects like { id: string, basePath: string } for arrays of structural nodes + if (item && typeof item === 'object' && item.id) { + return ( + + {buildChild(item.id, item.basePath)} + + ); + } + // Fallback for static string lists + if (typeof item === 'string') { + return {buildChild(item)}; + } + return null; + })} + + ); + } + + return null; +}; diff --git a/renderers/react/src/v0_9/catalog/basic/components/ReactChoicePicker.tsx b/renderers/react/src/v0_9/catalog/basic/components/ReactChoicePicker.tsx new file mode 100644 index 000000000..abf86eed0 --- /dev/null +++ b/renderers/react/src/v0_9/catalog/basic/components/ReactChoicePicker.tsx @@ -0,0 +1,113 @@ +/** + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React, {useState} from 'react'; +import {createReactComponent} from '../../../adapter'; +import {ChoicePickerApi} from '@a2ui/web_core/v0_9/basic_catalog'; +import {LEAF_MARGIN, STANDARD_BORDER, STANDARD_RADIUS} from '../utils'; + +export const ReactChoicePicker = createReactComponent(ChoicePickerApi, ({props, context}) => { + const [filter, setFilter] = useState(''); + + const values = Array.isArray(props.value) ? props.value : []; + const isMutuallyExclusive = props.variant === 'mutuallyExclusive'; + + const onToggle = (val: string) => { + if (isMutuallyExclusive) { + props.setValue([val]); + } else { + const newValues = values.includes(val) + ? values.filter((v: string) => v !== val) + : [...values, val]; + props.setValue(newValues); + } + }; + + const options = (props.options || []).filter( + (opt: any) => + !props.filterable || filter === '' || opt.label.toLowerCase().includes(filter.toLowerCase()) + ); + + const containerStyle: React.CSSProperties = { + display: 'flex', + flexDirection: 'column', + gap: '8px', + margin: LEAF_MARGIN, + width: '100%', + }; + + const listStyle: React.CSSProperties = { + display: 'flex', + flexDirection: props.displayStyle === 'chips' ? 'row' : 'column', + flexWrap: props.displayStyle === 'chips' ? 'wrap' : 'nowrap', + gap: '8px', + }; + + return ( +
+ {props.label && {props.label}} + {props.filterable && ( + setFilter(e.target.value)} + style={{padding: '4px 8px', border: STANDARD_BORDER, borderRadius: STANDARD_RADIUS}} + /> + )} +
+ {options.map((opt: any, i: number) => { + const isSelected = values.includes(opt.value); + if (props.displayStyle === 'chips') { + return ( + + ); + } + return ( + + ); + })} +
+
+ ); +}); diff --git a/renderers/react/src/v0_9/catalog/basic/components/ReactColumn.tsx b/renderers/react/src/v0_9/catalog/basic/components/ReactColumn.tsx new file mode 100644 index 000000000..20c74f855 --- /dev/null +++ b/renderers/react/src/v0_9/catalog/basic/components/ReactColumn.tsx @@ -0,0 +1,38 @@ +/** + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {createReactComponent} from '../../../adapter'; +import {ColumnApi} from '@a2ui/web_core/v0_9/basic_catalog'; +import {ReactChildList} from './ReactChildList'; +import {mapJustify, mapAlign} from '../utils'; + +export const ReactColumn = createReactComponent(ColumnApi, ({props, buildChild, context}) => { + return ( +
+ +
+ ); +}); diff --git a/renderers/react/src/v0_9/catalog/basic/components/ReactDateTimeInput.tsx b/renderers/react/src/v0_9/catalog/basic/components/ReactDateTimeInput.tsx new file mode 100644 index 000000000..cbab5f52f --- /dev/null +++ b/renderers/react/src/v0_9/catalog/basic/components/ReactDateTimeInput.tsx @@ -0,0 +1,68 @@ +/** + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import {createReactComponent} from '../../../adapter'; +import {DateTimeInputApi} from '@a2ui/web_core/v0_9/basic_catalog'; +import {LEAF_MARGIN, STANDARD_BORDER, STANDARD_RADIUS} from '../utils'; + +export const ReactDateTimeInput = createReactComponent(DateTimeInputApi, ({props}) => { + const onChange = (e: React.ChangeEvent) => { + props.setValue(e.target.value); + }; + + const uniqueId = React.useId(); + + // Map enableDate/enableTime to input type + let type = 'datetime-local'; + if (props.enableDate && !props.enableTime) type = 'date'; + if (!props.enableDate && props.enableTime) type = 'time'; + + const style: React.CSSProperties = { + padding: '8px', + width: '100%', + border: STANDARD_BORDER, + borderRadius: STANDARD_RADIUS, + boxSizing: 'border-box', + }; + + return ( +
+ {props.label && ( + + )} + +
+ ); +}); diff --git a/renderers/react/src/v0_9/catalog/basic/components/ReactDivider.tsx b/renderers/react/src/v0_9/catalog/basic/components/ReactDivider.tsx new file mode 100644 index 000000000..d0aa2e88b --- /dev/null +++ b/renderers/react/src/v0_9/catalog/basic/components/ReactDivider.tsx @@ -0,0 +1,39 @@ +/** + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import {createReactComponent} from '../../../adapter'; +import {DividerApi} from '@a2ui/web_core/v0_9/basic_catalog'; +import {LEAF_MARGIN} from '../utils'; + +export const ReactDivider = createReactComponent(DividerApi, ({props}) => { + const isVertical = props.axis === 'vertical'; + const style: React.CSSProperties = { + margin: LEAF_MARGIN, + border: 'none', + backgroundColor: '#ccc', + }; + + if (isVertical) { + style.width = '1px'; + style.height = '100%'; + } else { + style.width = '100%'; + style.height = '1px'; + } + + return
; +}); diff --git a/renderers/react/src/v0_9/catalog/basic/components/ReactIcon.tsx b/renderers/react/src/v0_9/catalog/basic/components/ReactIcon.tsx new file mode 100644 index 000000000..748c5579b --- /dev/null +++ b/renderers/react/src/v0_9/catalog/basic/components/ReactIcon.tsx @@ -0,0 +1,39 @@ +/** + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import {createReactComponent} from '../../../adapter'; +import {IconApi} from '@a2ui/web_core/v0_9/basic_catalog'; +import {getBaseLeafStyle} from '../utils'; + +export const ReactIcon = createReactComponent(IconApi, ({props}) => { + const iconName = typeof props.name === 'string' ? props.name : (props.name as any)?.path; + const style: React.CSSProperties = { + ...getBaseLeafStyle(), + fontSize: '24px', + width: '24px', + height: '24px', + display: 'inline-flex', + alignItems: 'center', + justifyContent: 'center', + }; + + return ( + + {iconName} + + ); +}); diff --git a/renderers/react/src/v0_9/catalog/basic/components/ReactImage.tsx b/renderers/react/src/v0_9/catalog/basic/components/ReactImage.tsx new file mode 100644 index 000000000..cb9e427f3 --- /dev/null +++ b/renderers/react/src/v0_9/catalog/basic/components/ReactImage.tsx @@ -0,0 +1,48 @@ +/** + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import {createReactComponent} from '../../../adapter'; +import {ImageApi} from '@a2ui/web_core/v0_9/basic_catalog'; +import {getBaseLeafStyle} from '../utils'; + +export const ReactImage = createReactComponent(ImageApi, ({props}) => { + const style: React.CSSProperties = { + ...getBaseLeafStyle(), + objectFit: props.fit as any, + width: '100%', + height: 'auto', + display: 'block', + }; + + if (props.variant === 'icon') { + style.width = '24px'; + style.height = '24px'; + } else if (props.variant === 'avatar') { + style.width = '40px'; + style.height = '40px'; + style.borderRadius = '50%'; + } else if (props.variant === 'smallFeature') { + style.maxWidth = '100px'; + } else if (props.variant === 'largeFeature') { + style.maxHeight = '400px'; + } else if (props.variant === 'header') { + style.height = '200px'; + style.objectFit = 'cover'; + } + + return ; +}); diff --git a/renderers/react/src/v0_9/catalog/basic/components/ReactList.tsx b/renderers/react/src/v0_9/catalog/basic/components/ReactList.tsx new file mode 100644 index 000000000..77e1e90de --- /dev/null +++ b/renderers/react/src/v0_9/catalog/basic/components/ReactList.tsx @@ -0,0 +1,41 @@ +/** + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import {createReactComponent} from '../../../adapter'; +import {ListApi} from '@a2ui/web_core/v0_9/basic_catalog'; +import {ReactChildList} from './ReactChildList'; +import {mapAlign} from '../utils'; + +export const ReactList = createReactComponent(ListApi, ({props, buildChild, context}) => { + const isHorizontal = props.direction === 'horizontal'; + const style: React.CSSProperties = { + display: 'flex', + flexDirection: isHorizontal ? 'row' : 'column', + alignItems: mapAlign(props.align), + overflowX: isHorizontal ? 'auto' : 'hidden', + overflowY: isHorizontal ? 'hidden' : 'auto', + width: '100%', + margin: 0, + padding: 0, + }; + + return ( +
+ +
+ ); +}); diff --git a/renderers/react/src/v0_9/catalog/basic/components/ReactModal.tsx b/renderers/react/src/v0_9/catalog/basic/components/ReactModal.tsx new file mode 100644 index 000000000..70bb51b2f --- /dev/null +++ b/renderers/react/src/v0_9/catalog/basic/components/ReactModal.tsx @@ -0,0 +1,77 @@ +/** + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {useState} from 'react'; +import {createReactComponent} from '../../../adapter'; +import {ModalApi} from '@a2ui/web_core/v0_9/basic_catalog'; + +export const ReactModal = createReactComponent(ModalApi, ({props, buildChild}) => { + const [isOpen, setIsOpen] = useState(false); + + return ( + <> +
setIsOpen(true)} style={{display: 'inline-block'}}> + {props.trigger ? buildChild(props.trigger) : null} +
+ {isOpen && ( +
setIsOpen(false)} + > +
e.stopPropagation()} + > + + {props.content ? buildChild(props.content) : null} +
+
+ )} + + ); +}); diff --git a/renderers/react/src/v0_9/catalog/basic/components/ReactRow.tsx b/renderers/react/src/v0_9/catalog/basic/components/ReactRow.tsx new file mode 100644 index 000000000..900c6fb2c --- /dev/null +++ b/renderers/react/src/v0_9/catalog/basic/components/ReactRow.tsx @@ -0,0 +1,38 @@ +/** + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {createReactComponent} from '../../../adapter'; +import {RowApi} from '@a2ui/web_core/v0_9/basic_catalog'; +import {ReactChildList} from './ReactChildList'; +import {mapJustify, mapAlign} from '../utils'; + +export const ReactRow = createReactComponent(RowApi, ({props, buildChild, context}) => { + return ( +
+ +
+ ); +}); diff --git a/renderers/react/src/v0_9/catalog/basic/components/ReactSlider.tsx b/renderers/react/src/v0_9/catalog/basic/components/ReactSlider.tsx new file mode 100644 index 000000000..9b4f02c00 --- /dev/null +++ b/renderers/react/src/v0_9/catalog/basic/components/ReactSlider.tsx @@ -0,0 +1,58 @@ +/** + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import {createReactComponent} from '../../../adapter'; +import {SliderApi} from '@a2ui/web_core/v0_9/basic_catalog'; +import {LEAF_MARGIN} from '../utils'; + +export const ReactSlider = createReactComponent(SliderApi, ({props}) => { + const onChange = (e: React.ChangeEvent) => { + props.setValue(Number(e.target.value)); + }; + + const uniqueId = React.useId(); + + return ( +
+
+ {props.label && ( + + )} + {props.value} +
+ +
+ ); +}); diff --git a/renderers/react/src/v0_9/catalog/basic/components/ReactTabs.tsx b/renderers/react/src/v0_9/catalog/basic/components/ReactTabs.tsx new file mode 100644 index 000000000..10ed1a4a0 --- /dev/null +++ b/renderers/react/src/v0_9/catalog/basic/components/ReactTabs.tsx @@ -0,0 +1,53 @@ +/** + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {useState} from 'react'; +import {createReactComponent} from '../../../adapter'; +import {TabsApi} from '@a2ui/web_core/v0_9/basic_catalog'; +import {LEAF_MARGIN} from '../utils'; + +export const ReactTabs = createReactComponent(TabsApi, ({props, buildChild}) => { + const [selectedIndex, setSelectedIndex] = useState(0); + + const tabs = props.tabs || []; + const activeTab = tabs[selectedIndex]; + + return ( +
+
+ {tabs.map((tab: any, i: number) => ( + + ))} +
+
{activeTab ? buildChild(activeTab.child) : null}
+
+ ); +}); diff --git a/renderers/react/src/v0_9/catalog/basic/components/ReactText.tsx b/renderers/react/src/v0_9/catalog/basic/components/ReactText.tsx new file mode 100644 index 000000000..a4c5d631a --- /dev/null +++ b/renderers/react/src/v0_9/catalog/basic/components/ReactText.tsx @@ -0,0 +1,46 @@ +/** + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import {createReactComponent} from '../../../adapter'; +import {TextApi} from '@a2ui/web_core/v0_9/basic_catalog'; +import {getBaseLeafStyle} from '../utils'; + +export const ReactText = createReactComponent(TextApi, ({props}) => { + const text = props.text ?? ''; + const style: React.CSSProperties = { + ...getBaseLeafStyle(), + display: 'inline-block', + }; + + switch (props.variant) { + case 'h1': + return

{text}

; + case 'h2': + return

{text}

; + case 'h3': + return

{text}

; + case 'h4': + return

{text}

; + case 'h5': + return
{text}
; + case 'caption': + return {text}; + case 'body': + default: + return {text}; + } +}); diff --git a/renderers/react/src/v0_9/catalog/basic/components/ReactTextField.tsx b/renderers/react/src/v0_9/catalog/basic/components/ReactTextField.tsx new file mode 100644 index 000000000..1c2b17ce9 --- /dev/null +++ b/renderers/react/src/v0_9/catalog/basic/components/ReactTextField.tsx @@ -0,0 +1,82 @@ +/** + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import {createReactComponent} from '../../../adapter'; +import {TextFieldApi} from '@a2ui/web_core/v0_9/basic_catalog'; +import {LEAF_MARGIN, STANDARD_BORDER, STANDARD_RADIUS} from '../utils'; + +export const ReactTextField = createReactComponent(TextFieldApi, ({props}) => { + const onChange = (e: React.ChangeEvent) => { + props.setValue(e.target.value); + }; + + const isLong = props.variant === 'longText'; + const type = + props.variant === 'number' ? 'number' : props.variant === 'obscured' ? 'password' : 'text'; + + const style: React.CSSProperties = { + padding: '8px', + width: '100%', + border: STANDARD_BORDER, + borderRadius: STANDARD_RADIUS, + boxSizing: 'border-box', + }; + + // Note: To have a unique id without passing context we can use a random or provided id, + // but the simplest is just relying on React's useId if we really need it. + // For now, we'll omit the `id` from the label connection since we removed context. + const uniqueId = React.useId(); + + const hasError = props.validationErrors && props.validationErrors.length > 0; + + return ( +
+ {props.label && ( + + )} + {isLong ? ( +