diff --git a/.codepress/dev-server/Dockerfile.editor b/.codepress/dev-server/Dockerfile.editor new file mode 100644 index 000000000..5f7192445 --- /dev/null +++ b/.codepress/dev-server/Dockerfile.editor @@ -0,0 +1,38 @@ +# Generated by CodePress bootstrap-dev-server. +# Dev-mode image for the "editor" frontend (Live Dev Server). +# Edits are preserved, but running /codepress-bootstrap-dev-server again may overwrite them. +FROM public.ecr.aws/docker/library/node:22-bookworm + +# System packages the dev runtime needs. `procps` only: every native-ish dependency +# here (onnxruntime-web, @huggingface/transformers, mediabunny) ships WebAssembly or +# prebuilt binaries, so nothing compiles against a system library at install time. +RUN apt-get update \ + && apt-get install -y --no-install-recommends procps \ + && rm -rf /var/lib/apt/lists/* + +# npm 11.8.0 is the repo's declared packageManager; activate that exact version so a +# cold start never pauses to fetch a package manager. +RUN corepack enable && corepack prepare npm@11.8.0 --activate +WORKDIR /app + +# THIN image: no `node_modules`, no source COPY. The dev-server runtime provides +# dependencies at run time (squashfs hydration, or `npm install` in this image +# against the bind-mounted checkout). Only the toolchain lives here. + +# HMR + bind config — values come from the runtime, never hardcoded. vite.config.ts +# reads CODEPRESS_HMR_PROTOCOL / CODEPRESS_HMR_CLIENT_PORT into `server.hmr`. +ENV HOSTNAME=0.0.0.0 \ + CODEPRESS_BIND_HOST=0.0.0.0 \ + PORT=5173 \ + CODEPRESS_HMR_CLIENT_PORT=443 \ + CODEPRESS_HMR_PROTOCOL=wss + +EXPOSE 5173 + +# Single root app, so only the root bin dir. Populated at run time on the +# bind-mounted checkout; prepended so the corepack shims survive. +ENV PATH="/app/node_modules/.bin:${PATH}" + +# Dev command (HMR on). `vp` is vite-plus, the repo's Vite toolchain wrapper; `vp dev` +# is its alias for the dev server and takes Vite's own --host/--port. +CMD ["sh", "-c", "npm exec --no -- vp dev --host \"${CODEPRESS_BIND_HOST:-0.0.0.0}\" --port \"$PORT\""] diff --git a/.codepress/dev-server/recipe.json b/.codepress/dev-server/recipe.json new file mode 100644 index 000000000..db09a9d15 --- /dev/null +++ b/.codepress/dev-server/recipe.json @@ -0,0 +1,30 @@ +{ + "schema_version": 1, + "bootstrapped_at": "2026-09-04T16:32:20Z", + "discovery_branch": "codepress/stevekriz/setup-storybook-component-catalog-91f1ea3a", + "frontends": [ + { + "label": "editor", + "working_dir": "", + "description": "FreeCut — the browser-based multi-track video editor (the whole app; there is no separate site or admin).", + "dockerfile_path": ".codepress/dev-server/Dockerfile.editor", + "dev_command": "npm exec --no -- vp dev --host \"${CODEPRESS_BIND_HOST:-0.0.0.0}\" --port \"$PORT\"", + "prebuild_command": "", + "prebuild_inputs": [], + "framework": "vite", + "package_manager": "npm", + "install_command": "npm install", + "dependency_manifests": ["package-lock.json"], + "dev_port": 5173, + "system_packages": ["procps"], + "size": "large", + "companions": [ + { + "label": "storybook", + "dev_command": "npm exec --no -- storybook dev -p \"$PORT\" -h \"${CODEPRESS_BIND_HOST:-0.0.0.0}\" --ci --no-open", + "dev_port": 6006 + } + ] + } + ] +} diff --git a/.fallowrc.json b/.fallowrc.json index c386adec1..2e57225bb 100644 --- a/.fallowrc.json +++ b/.fallowrc.json @@ -12,7 +12,12 @@ "ignorePatterns": [ // Static reachability cannot see URL-loaded assets such as /sw.js // and /moss-tts/moss_tts.worker.js. - "public/**" + "public/**", + // Storybook loads *.stories.tsx through its own glob, so every story export + // is unreachable from the app entries by construction. Ignoring them keeps + // the dead-code ratchet meaningful instead of demanding an allowlist entry + // per story — and keeps stories from counting as "usage" of a component. + "**/*.stories.tsx" ], "duplicates": { // Hide pair-only clones; focus on widespread copy-paste diff --git a/.gitignore b/.gitignore index 54bffb85c..482284d45 100644 --- a/.gitignore +++ b/.gitignore @@ -101,3 +101,6 @@ ds-bundle/ artifacts/ .playwright-cli/ + +# Storybook production build output +storybook-static diff --git a/.storybook/main.ts b/.storybook/main.ts new file mode 100644 index 000000000..f23838b3d --- /dev/null +++ b/.storybook/main.ts @@ -0,0 +1,51 @@ +import type { StorybookConfig } from '@storybook/react-vite' + +/** + * Hosts allowed to reach the Storybook dev server and its manager websocket. + * + * CodePress serves the preview from a public proxied origin, and Storybook validates + * the websocket Origin independently of Vite. The two static suffixes cover the + * production and staging preview domains; `__VITE_ADDITIONAL_SERVER_ALLOWED_HOSTS` is + * injected at runtime and carries the MicroVM endpoint host, which differs per + * environment. All three must be present — a non-empty allowlist disables the + * allow-all fallback, so listing one environment alone would 403 the other. + */ +const previewAllowedHosts = ['.preview.codepress.dev', '.preview-staging.codepress.dev'] + .concat((process.env.__VITE_ADDITIONAL_SERVER_ALLOWED_HOSTS ?? '').split(',')) + .map((host) => host.trim()) + .filter(Boolean) + +const config: StorybookConfig = { + stories: ['../src/**/*.stories.tsx'], + framework: { + name: '@storybook/react-vite', + options: { + builder: { + // Not the app config — see the header comment in vite.storybook.config.ts. + viteConfigPath: 'vite.storybook.config.ts', + }, + }, + }, + core: { + disableTelemetry: true, + disableWhatsNewNotifications: true, + allowedHosts: previewAllowedHosts, + }, + viteFinal: (viteConfig) => ({ + ...viteConfig, + server: { + ...viteConfig.server, + // The preview origin terminates HTTPS on 443, so the HMR client must dial the + // proxy rather than the container's own dev port. Both values are injected by + // the CodePress runtime; locally the defaults keep plain same-port websockets. + hmr: { + protocol: (process.env.CODEPRESS_HMR_PROTOCOL ?? 'ws') as 'ws' | 'wss', + ...(process.env.CODEPRESS_HMR_CLIENT_PORT + ? { clientPort: Number.parseInt(process.env.CODEPRESS_HMR_CLIENT_PORT, 10) } + : {}), + }, + }, + }), +} + +export default config diff --git a/.storybook/manager.ts b/.storybook/manager.ts new file mode 100644 index 000000000..c66b01e30 --- /dev/null +++ b/.storybook/manager.ts @@ -0,0 +1,6 @@ +// The catalog is a dark-room tool like the editor it documents; the light manager +// chrome against near-black story canvases is a jarring pair. +import { addons } from 'storybook/manager-api' +import { themes } from 'storybook/theming' + +addons.setConfig({ theme: themes.dark }) diff --git a/.storybook/preview-head.html b/.storybook/preview-head.html new file mode 100644 index 000000000..2d03df4b7 --- /dev/null +++ b/.storybook/preview-head.html @@ -0,0 +1,9 @@ + + + + diff --git a/.storybook/preview.tsx b/.storybook/preview.tsx new file mode 100644 index 000000000..5cecd65ad --- /dev/null +++ b/.storybook/preview.tsx @@ -0,0 +1,41 @@ +import type { Decorator, Preview } from '@storybook/react-vite' +import { TooltipProvider } from '@/components/ui/tooltip' +// Side-effect imports: the app's global stylesheet (Tailwind theme, OKLCH tokens, +// timeline theme extension, animation utilities) and the i18next instance that +// translated components — Dialog, FloatingPanel, LanguageSwitcher — read from. +import '@/index.css' +import '@/i18n' + +/** + * FreeCut is dark-only by design, so every story renders on the app background with + * the shared tooltip provider already mounted — the same chrome a component sees + * inside the editor. + */ +const withEditorSurface: Decorator = (Story) => ( + +
+ +
+
+) + +const preview: Preview = { + decorators: [withEditorSurface], + parameters: { + // The decorator owns padding, and panels/overlays need the full frame. + layout: 'fullscreen', + controls: { + matchers: { + color: /(background|color)$/i, + date: /Date$/i, + }, + }, + options: { + storySort: { + order: ['Foundations', 'UI', 'Property Controls', 'Editor Surfaces', 'Brand'], + }, + }, + }, +} + +export default preview diff --git a/package-lock.json b/package-lock.json index f32878f6d..4836c7d7d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -61,6 +61,7 @@ "zustand": "5.0.12" }, "devDependencies": { + "@storybook/react-vite": "10.6.0", "@tailwindcss/vite": "4.2.2", "@tanstack/router-cli": "1.166.33", "@testing-library/dom": "10.4.1", @@ -74,6 +75,7 @@ "@webgpu/types": "0.1.69", "jsdom": "27.4.0", "playwright": "1.60.0", + "storybook": "10.6.0", "tailwindcss": "4.2.2", "typescript": "7.0.2", "vite-plus": "0.2.4" @@ -1602,6 +1604,26 @@ "node": ">=18.0.0" } }, + "node_modules/@joshwooding/vite-plugin-react-docgen-typescript": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@joshwooding/vite-plugin-react-docgen-typescript/-/vite-plugin-react-docgen-typescript-0.7.0.tgz", + "integrity": "sha512-qvsTEwEFefhdirGOPnu9Wp6ChfIwy2dBCRuETU3uE+4cC+PFoxMSiiEhxk4lOluA34eARHA0OxqsEUYDqRMgeQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "glob": "^13.0.1", + "react-docgen-typescript": "^2.2.2" + }, + "peerDependencies": { + "typescript": ">= 4.3.x", + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.13", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", @@ -1648,113 +1670,783 @@ "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@lottiefiles/dotlottie-web": { - "version": "0.76.0", - "resolved": "https://registry.npmjs.org/@lottiefiles/dotlottie-web/-/dotlottie-web-0.76.0.tgz", - "integrity": "sha512-uWJ86UJM6hjN4MY2aGSyyFcRQEAM4B9qDCnb/336dHab1zE6nyOF45b90t8xesZPwNtP/2moNGMrMQ1UJW6+lQ==", - "license": "MIT", - "engines": { - "node": ">=18.17.0", - "npm": ">=9.5.0" - } - }, - "node_modules/@mediabunny/aac-encoder": { - "version": "1.50.8", - "resolved": "https://registry.npmjs.org/@mediabunny/aac-encoder/-/aac-encoder-1.50.8.tgz", - "integrity": "sha512-A5Se/LZd6RmYq/h36lBMSEsHvsyW8d0toR7FrAwpsFYbK+DVQYf90KiBT1Aw/mzLXx8/ypIOORJnd1sVZqOvJQ==", - "license": "MPL-2.0", - "funding": { - "type": "individual", - "url": "https://github.com/sponsors/Vanilagy" - }, - "peerDependencies": { - "mediabunny": "^1.0.0" - } - }, - "node_modules/@mediabunny/ac3": { - "version": "1.50.8", - "resolved": "https://registry.npmjs.org/@mediabunny/ac3/-/ac3-1.50.8.tgz", - "integrity": "sha512-B33jqHpGRA1dOmjs5Bcq0B5YGciDjlcMuS+kGcUqgEJ5ExEs9EX+DCjZj7W+7/WOqAQDf4/BZxUaExLYmtZREA==", - "license": "MPL-2.0", - "funding": { - "type": "individual", - "url": "https://github.com/sponsors/Vanilagy" - }, - "peerDependencies": { - "mediabunny": "^1.0.0" - } - }, - "node_modules/@mediabunny/mp3-encoder": { - "version": "1.50.8", - "resolved": "https://registry.npmjs.org/@mediabunny/mp3-encoder/-/mp3-encoder-1.50.8.tgz", - "integrity": "sha512-eBT/H30tTu8AmZXqZ5RTpJ9VmwVlwednajuOrrWp0GS6cbGXsGMQ60Qvr3ZMIE0QDiadlEzb8/ozR+doP+MC1g==", - "license": "MPL-2.0", - "funding": { - "type": "individual", - "url": "https://github.com/sponsors/Vanilagy" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@lottiefiles/dotlottie-web": { + "version": "0.76.0", + "resolved": "https://registry.npmjs.org/@lottiefiles/dotlottie-web/-/dotlottie-web-0.76.0.tgz", + "integrity": "sha512-uWJ86UJM6hjN4MY2aGSyyFcRQEAM4B9qDCnb/336dHab1zE6nyOF45b90t8xesZPwNtP/2moNGMrMQ1UJW6+lQ==", + "license": "MIT", + "engines": { + "node": ">=18.17.0", + "npm": ">=9.5.0" + } + }, + "node_modules/@mediabunny/aac-encoder": { + "version": "1.50.8", + "resolved": "https://registry.npmjs.org/@mediabunny/aac-encoder/-/aac-encoder-1.50.8.tgz", + "integrity": "sha512-A5Se/LZd6RmYq/h36lBMSEsHvsyW8d0toR7FrAwpsFYbK+DVQYf90KiBT1Aw/mzLXx8/ypIOORJnd1sVZqOvJQ==", + "license": "MPL-2.0", + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/Vanilagy" + }, + "peerDependencies": { + "mediabunny": "^1.0.0" + } + }, + "node_modules/@mediabunny/ac3": { + "version": "1.50.8", + "resolved": "https://registry.npmjs.org/@mediabunny/ac3/-/ac3-1.50.8.tgz", + "integrity": "sha512-B33jqHpGRA1dOmjs5Bcq0B5YGciDjlcMuS+kGcUqgEJ5ExEs9EX+DCjZj7W+7/WOqAQDf4/BZxUaExLYmtZREA==", + "license": "MPL-2.0", + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/Vanilagy" + }, + "peerDependencies": { + "mediabunny": "^1.0.0" + } + }, + "node_modules/@mediabunny/mp3-encoder": { + "version": "1.50.8", + "resolved": "https://registry.npmjs.org/@mediabunny/mp3-encoder/-/mp3-encoder-1.50.8.tgz", + "integrity": "sha512-eBT/H30tTu8AmZXqZ5RTpJ9VmwVlwednajuOrrWp0GS6cbGXsGMQ60Qvr3ZMIE0QDiadlEzb8/ozR+doP+MC1g==", + "license": "MPL-2.0", + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/Vanilagy" + }, + "peerDependencies": { + "mediabunny": "^1.0.0" + } + }, + "node_modules/@mediabunny/prores": { + "version": "1.50.8", + "resolved": "https://registry.npmjs.org/@mediabunny/prores/-/prores-1.50.8.tgz", + "integrity": "sha512-PBitr6u8RZTcA9H8k3Gsscw+8Xr+A9DrSygi5jwlIZ6dZHL5e7K4vHoC1Repe5yN6X1hAo4rf/Pm0/s0gM+7Mw==", + "license": "MPL-2.0", + "dependencies": { + "turbores": "^1.2.2" + }, + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/Vanilagy" + }, + "peerDependencies": { + "mediabunny": "^1.49.0" + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.6.tgz", + "integrity": "sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.3" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" + } + }, + "node_modules/@oxc-parser/binding-android-arm-eabi": { + "version": "0.127.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-android-arm-eabi/-/binding-android-arm-eabi-0.127.0.tgz", + "integrity": "sha512-0LC7ye4hvqbIKxAzThzvswgHLFu2AURKzYLeSVvLdu2TBOYWQDmHnTqPLeA597BcUCxiLqLsS4CJ5uoI5WYWCQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-android-arm64": { + "version": "0.127.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-android-arm64/-/binding-android-arm64-0.127.0.tgz", + "integrity": "sha512-b5jtVTH6AU5CJXHNdj7Jj9IEiR9yVjjnwHzPJhGyHGPdcsZSzBCkS9GBbV33niRMvKthDwQRFRJfI4a+k4PvYg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-darwin-arm64": { + "version": "0.127.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-darwin-arm64/-/binding-darwin-arm64-0.127.0.tgz", + "integrity": "sha512-obCE8B7ISKkJidjlhv9xRGJPOSDG2Yu6PRga9Ruaz35uintHxbp1Ki/Yc71wx4rj3Edrm0a1kzG1TAwit0wFpg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-darwin-x64": { + "version": "0.127.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-darwin-x64/-/binding-darwin-x64-0.127.0.tgz", + "integrity": "sha512-JL6Xb5IwPQT8rUzlpsX7E+AgfcdNklXNPFp8pjCQQ5MQOQo5rtEB2ui+3Hgg9Sn7Y9Egj6YOLLiHhLpdAe12Aw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-freebsd-x64": { + "version": "0.127.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-freebsd-x64/-/binding-freebsd-x64-0.127.0.tgz", + "integrity": "sha512-SDQ/3MQFw58fqQz3Z1PhSKFF3JoCF4gmlNjziDm8X02tTahCw0qJbd7FGPDKw1i4VTBZene9JPyC3mHtSvi+wA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-arm-gnueabihf": { + "version": "0.127.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-0.127.0.tgz", + "integrity": "sha512-Av+D1MIqzV0YMGPT9we2SIZaMKD7Cxs4CvXSx/yxaWHewZjYEjScpOf5igc8IILASViw4WTnjlwUdI1KzVtDHQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-arm-musleabihf": { + "version": "0.127.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-0.127.0.tgz", + "integrity": "sha512-Cs2fdJ8cPpFdeebj6p4dag8A4+56hPvZ0AhQQzlaLswGz1tz7bXt1nETLeorrM9+AMcWFFkqxcXwDGfTVidY8g==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-arm64-gnu": { + "version": "0.127.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.127.0.tgz", + "integrity": "sha512-qdOfTcT6SY8gsJrrV92uyEUyjqMGPpIB5JZUG6QN5dukYd+7/j0kX6MwK1DgQj39jtUYixxPiaRUiEN1+0CXgQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-arm64-musl": { + "version": "0.127.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.127.0.tgz", + "integrity": "sha512-EoTCZneNFU/P2qrpEM+RHmQwt+CvDkyGESG6qhr7KaegXLZwePfbrkCDfAk8/rhxbDUVGsZILX+2tqPzFtoFWA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-ppc64-gnu": { + "version": "0.127.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-0.127.0.tgz", + "integrity": "sha512-zALjmZYgxFLHjXeudcDF0xFGNydTAtkAeXAr2EuC17ywCyFxcmQra4w0BMde0Yi/re4Bi4iwEoEXtYN7l6eBLQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-riscv64-gnu": { + "version": "0.127.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-0.127.0.tgz", + "integrity": "sha512-fPP8M6zQLS7Jz7o9d5ArUSuAuSK3e+WCYVrCpdzeCOejidtZExJ9tjhDrAd3HEPqARBCPmdpqxESPFqy44vkBQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-riscv64-musl": { + "version": "0.127.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-0.127.0.tgz", + "integrity": "sha512-7IcC4Ao02oGpfnjt+X/oF4U2mllo2qoSkw5xxiXNKL9MCTsTiAC6616beOuehdxGcnz1bRoPC1RQ2f1GQDdN+g==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-s390x-gnu": { + "version": "0.127.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-0.127.0.tgz", + "integrity": "sha512-pbXIhiNFHoqWeqDNLiJ9JkpHz1IM9k4DXa66x+1GTWMG7iLxtkXgE53iiuKSXwmk3zIYmaPVfBvgcAhS583K4Q==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-x64-gnu": { + "version": "0.127.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.127.0.tgz", + "integrity": "sha512-MYCguB9RvBvlSd6gbuNI7QwiLoCCAlGnlRJFPrzLI6U1/9wkC/WK6LtBAUln55H1Ctqw45PWmqrobKoMhsYQzQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-x64-musl": { + "version": "0.127.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-x64-musl/-/binding-linux-x64-musl-0.127.0.tgz", + "integrity": "sha512-5eY0B/bxf1xIUxb4NOTvOI3KWtBQfPWYyKAzgcrCt0mDibSZygVpO1Pz8bkeiSZ5Jj9+M09dkggG3H8I5d0Uyg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-openharmony-arm64": { + "version": "0.127.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-openharmony-arm64/-/binding-openharmony-arm64-0.127.0.tgz", + "integrity": "sha512-Gld0ajrFTUXNtdw20fVBuTQx66FA75nIVg+//pPfR3sXkuABB4mTBhl3r9JNzrJpgW//qiwxf0nWXUWGJSL3UQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-wasm32-wasi": { + "version": "0.127.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-wasm32-wasi/-/binding-wasm32-wasi-0.127.0.tgz", + "integrity": "sha512-T6KVD7rhLzFlwGRXMnxUFfkCZD8FHnb968wVXW1mXzgRFc5RNXOBY2mPPDZ77x5Ln76ltLMgtPg0cOkU1NSrEQ==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "1.9.2", + "@emnapi/runtime": "1.9.2", + "@napi-rs/wasm-runtime": "^1.1.4" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-wasm32-wasi/node_modules/@emnapi/core": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.2.tgz", + "integrity": "sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.1", + "tslib": "^2.4.0" + } + }, + "node_modules/@oxc-parser/binding-wasm32-wasi/node_modules/@emnapi/runtime": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.2.tgz", + "integrity": "sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@oxc-parser/binding-wasm32-wasi/node_modules/@emnapi/wasi-threads": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", + "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@oxc-parser/binding-win32-arm64-msvc": { + "version": "0.127.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-0.127.0.tgz", + "integrity": "sha512-Ujvw4X+LD1CCGULcsQcvb4YNVoBGqt+JHgNNzGGaCImELiZLk477ifUH53gIbE7EKd933NdTi25JWEr9K2HwXw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-win32-ia32-msvc": { + "version": "0.127.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-0.127.0.tgz", + "integrity": "sha512-0cwxKO7KHQQQfo4Uf4B2SQrhgm+cJaP9OvFFhx52Tkg4bezsacu83GB2/In5bC415Ueeym+kXdnge/57rbSfTw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-win32-x64-msvc": { + "version": "0.127.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-win32-x64-msvc/-/binding-win32-x64-msvc-0.127.0.tgz", + "integrity": "sha512-rOrnSQSCbhI2kowr9XxE7m9a8oQXnBHjnS6j95LxxAnEZ0+Fz20WlRXG4ondQb+ejjt2KOsa65sE6++L6kUd+w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-project/runtime": { + "version": "0.138.0", + "resolved": "https://registry.npmjs.org/@oxc-project/runtime/-/runtime-0.138.0.tgz", + "integrity": "sha512-yHhoXsN8tYxgdJCdD91PbySNjEEaBX/tH2OQRDXJpsQv5b184oC4/qVbU7qlblvfil/JP15Lh2HW7+HN5DS90Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-project/types": { + "version": "0.139.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.139.0.tgz", + "integrity": "sha512-r9gHphtCs+1M7J0pw6Sn/hh/Wpa/iQrOOkrNAlVLF/gHq+/CJmHIWKKUUhdWjcD6CIa8idarspCsASiXCXvFUw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/@oxc-resolver/binding-android-arm-eabi": { + "version": "11.21.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-android-arm-eabi/-/binding-android-arm-eabi-11.21.2.tgz", + "integrity": "sha512-xQoCRv+gKax9KTdwdaQNnAFOai8neay7g3jExDIORzhbrejwGSJaZNTdOJHR5ziLg2joMxOCMOFMo4zuxza2uQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@oxc-resolver/binding-android-arm64": { + "version": "11.21.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-android-arm64/-/binding-android-arm64-11.21.2.tgz", + "integrity": "sha512-HF5oiE2L05yInPYCFD/4uxSrEZW4SuIfn99Y6L1xnJnzl066JR+MJs2rIdstw8A2MPlAKH+13dpFPNycjqzvGg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@oxc-resolver/binding-darwin-arm64": { + "version": "11.21.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-darwin-arm64/-/binding-darwin-arm64-11.21.2.tgz", + "integrity": "sha512-UX4u49CVCAD8QZNELaW8eMGgMAGwFWYEPbvNsh+3r/gs4NX3KfpiACMVwRQT0EuH3uat9hM5Zl+Ppm9pJD8tgg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@oxc-resolver/binding-darwin-x64": { + "version": "11.21.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-darwin-x64/-/binding-darwin-x64-11.21.2.tgz", + "integrity": "sha512-J9xPx7YBkrRmJ+xl561ztnMWEc1aOyjEIxBiGX1dVb3u7bGSnfObfcZk+Pd+uM0HZAPNsQ1xvD8j52A/uOSqNQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@oxc-resolver/binding-freebsd-x64": { + "version": "11.21.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-freebsd-x64/-/binding-freebsd-x64-11.21.2.tgz", + "integrity": "sha512-fRlt7OvSaQkWj6+EDTVxawVxOlqJB2QSnBfkeCyK4RTvsGctbw3BiH2Tb7DzMs7bikc4BRBpvWP5zF9K8b54Zg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@oxc-resolver/binding-linux-arm-gnueabihf": { + "version": "11.21.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-11.21.2.tgz", + "integrity": "sha512-gK+vPUcPQITkGwBKpZGrcDHSlU6eDGl7AQacxS2CEKAZIBHWkOVFeJwLZ4tYnA1acJqRM5lt7yYwPCVqGHIJ7A==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oxc-resolver/binding-linux-arm-musleabihf": { + "version": "11.21.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-11.21.2.tgz", + "integrity": "sha512-L/Rgas7SrOKy/z7IH+HxSFRqVO4PuLDKLEGKvnhoCBBq3UJ0YzGBou3qMzaAGgkJwsIvX2pBF+7ojzfUhLiZxQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oxc-resolver/binding-linux-arm64-gnu": { + "version": "11.21.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-11.21.2.tgz", + "integrity": "sha512-CUEYvlX1Fk7E9kUMzuswru1J9HLxMwnpDeQGjQuI4ZH+iNCoa2X9T+pvyzrbsgl7WnIeTFTlNlHsRfVdf5g9/g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oxc-resolver/binding-linux-arm64-musl": { + "version": "11.21.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm64-musl/-/binding-linux-arm64-musl-11.21.2.tgz", + "integrity": "sha512-ViN1ZibQyxwC67GpoP33oo+S9UyUnkog13vzQb9+v9bCNvrVzJuk0MRdacjtv/9xfRMVF/eqHFyl8YOeykI10Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oxc-resolver/binding-linux-ppc64-gnu": { + "version": "11.21.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-11.21.2.tgz", + "integrity": "sha512-CU1sCqWnhGqYD5I1HedHk5pujrn7ssDkNB/AEQd/pd3D/EojVSgJUlpbafwIbyhia3PgIfkvdFpRPWSALzVumA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oxc-resolver/binding-linux-riscv64-gnu": { + "version": "11.21.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-11.21.2.tgz", + "integrity": "sha512-jWVyZtIHca4Gb96x7dag+y69vlei7ffjrsveLkmf2ZhqEAz6ZSBnY1GWvgZUaZlwZP62A3xD092BW97Q5VGc+g==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oxc-resolver/binding-linux-riscv64-musl": { + "version": "11.21.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-11.21.2.tgz", + "integrity": "sha512-LF29obFqNgBUgDX7rmUK7M4D0JQG5LxhYzn3xXmECcHU9aQAdWG7NiY052qybtesEdwHQXKNTWYQ7mTsybNvWg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oxc-resolver/binding-linux-s390x-gnu": { + "version": "11.21.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-11.21.2.tgz", + "integrity": "sha512-+NYcm+cCHBbtdQQ3A4phQTSuVRYnNHz7wrl9XRAPEovcdoqi0mb1K5ZOl+jN54ZD+q1zz3V0vltbFJmzecJKmw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oxc-resolver/binding-linux-x64-gnu": { + "version": "11.21.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-x64-gnu/-/binding-linux-x64-gnu-11.21.2.tgz", + "integrity": "sha512-UQqZDdG2r2HhAOsZEgufkIWHPQ886IUyuJQkoZByvzhW8j51R4UNzGBJFkTiTnLhQnggwJRdJgFWK4uY6ZVIMw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oxc-resolver/binding-linux-x64-musl": { + "version": "11.21.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-x64-musl/-/binding-linux-x64-musl-11.21.2.tgz", + "integrity": "sha512-3Q9PMRjalWkT6NZ4jfujuqTCFwoWErg3y3BnOgb544B8IMw4PktiwWOigMfOHNRLMghZeJ7hpfpZf4CP7rV7Og==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oxc-resolver/binding-openharmony-arm64": { + "version": "11.21.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-openharmony-arm64/-/binding-openharmony-arm64-11.21.2.tgz", + "integrity": "sha512-Eljeq3ndtyKhM+Es8LITi4Zl2htzuRZcrPMF3kMCsrILztvU6AjZ3FuEhHHKobPUB9rMpzLpJP5bDqXI7r+iog==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@oxc-resolver/binding-wasm32-wasi": { + "version": "11.21.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-wasm32-wasi/-/binding-wasm32-wasi-11.21.2.tgz", + "integrity": "sha512-HGDbNsIywqc4LxU38+CTJNnB/6BF7rheWOJ259b4eE0aEnelYblC8x+1tEd63bp31fYne63RQz9Jb4yVnC7Yig==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "1.11.0", + "@emnapi/runtime": "1.11.0", + "@napi-rs/wasm-runtime": "^1.1.5" }, - "peerDependencies": { - "mediabunny": "^1.0.0" + "engines": { + "node": ">=14.0.0" } }, - "node_modules/@mediabunny/prores": { - "version": "1.50.8", - "resolved": "https://registry.npmjs.org/@mediabunny/prores/-/prores-1.50.8.tgz", - "integrity": "sha512-PBitr6u8RZTcA9H8k3Gsscw+8Xr+A9DrSygi5jwlIZ6dZHL5e7K4vHoC1Repe5yN6X1hAo4rf/Pm0/s0gM+7Mw==", - "license": "MPL-2.0", + "node_modules/@oxc-resolver/binding-wasm32-wasi/node_modules/@emnapi/core": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.0.tgz", + "integrity": "sha512-l9Oo58x0HOP5znGzVhYW9U3e5wVuA4LAZU2AGezTmkhO1CgQRFDhDg4nneHsu/t3WniXg9QrG2nIXL/ZS8ln8Q==", + "dev": true, + "license": "MIT", + "optional": true, "dependencies": { - "turbores": "^1.2.2" - }, - "funding": { - "type": "individual", - "url": "https://github.com/sponsors/Vanilagy" - }, - "peerDependencies": { - "mediabunny": "^1.49.0" + "@emnapi/wasi-threads": "1.2.2", + "tslib": "^2.4.0" } }, - "node_modules/@napi-rs/wasm-runtime": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.6.tgz", - "integrity": "sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==", + "node_modules/@oxc-resolver/binding-wasm32-wasi/node_modules/@emnapi/runtime": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.0.tgz", + "integrity": "sha512-55coeOFKHv1ywEcUXJtWU5f+Jr/W5tZDvZig8DLKSwUN1JpROQ4rk/SNOQiFWmaR/VKF4zuFyW1B8JduOSv6Pg==", "dev": true, "license": "MIT", "optional": true, "dependencies": { - "@tybys/wasm-util": "^0.10.3" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Brooooooklyn" - }, - "peerDependencies": { - "@emnapi/core": "^1.7.1", - "@emnapi/runtime": "^1.7.1" + "tslib": "^2.4.0" } }, - "node_modules/@oxc-project/runtime": { - "version": "0.138.0", - "resolved": "https://registry.npmjs.org/@oxc-project/runtime/-/runtime-0.138.0.tgz", - "integrity": "sha512-yHhoXsN8tYxgdJCdD91PbySNjEEaBX/tH2OQRDXJpsQv5b184oC4/qVbU7qlblvfil/JP15Lh2HW7+HN5DS90Q==", + "node_modules/@oxc-resolver/binding-win32-arm64-msvc": { + "version": "11.21.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-11.21.2.tgz", + "integrity": "sha512-iWx25CBEgH49iE9q5coEGI/jb1jl5kkCY9z6U5Og67xCkQ/WFMDc2J5U78+AE91SUxM2NqSLhJC8/PLfWnImww==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "engines": { - "node": "^20.19.0 || >=22.12.0" - } + "optional": true, + "os": [ + "win32" + ] }, - "node_modules/@oxc-project/types": { - "version": "0.139.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.139.0.tgz", - "integrity": "sha512-r9gHphtCs+1M7J0pw6Sn/hh/Wpa/iQrOOkrNAlVLF/gHq+/CJmHIWKKUUhdWjcD6CIa8idarspCsASiXCXvFUw==", + "node_modules/@oxc-resolver/binding-win32-x64-msvc": { + "version": "11.21.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-win32-x64-msvc/-/binding-win32-x64-msvc-11.21.2.tgz", + "integrity": "sha512-VPoCAhKvCQTlG7vxqaBXcmuvbh77BfnGXj8g0pbvVXpm1F/R8rDVwqIWcEbMzrI1JvJlm8v7T9uMVQb6UctMRg==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/Boshen" - } + "optional": true, + "os": [ + "win32" + ] }, "node_modules/@oxfmt/binding-android-arm-eabi": { "version": "0.57.0", @@ -4092,6 +4784,49 @@ "dev": true, "license": "MIT" }, + "node_modules/@rollup/pluginutils": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.4.0.tgz", + "integrity": "sha512-MfPp06CjRLfXQ3wY0R8vJDYBy/MvVcc9OulEfR0B8Iv9ko+GCNaRZ+EpJYFl27LhKsZK0o420sYCRHCjfCgeUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils/node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/pluginutils/node_modules/picomatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/@rollup/rollup-linux-x64-gnu": { "version": "4.62.1", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.62.1.tgz", @@ -4118,6 +4853,147 @@ "integrity": "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==", "license": "MIT" }, + "node_modules/@storybook/builder-vite": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/@storybook/builder-vite/-/builder-vite-10.6.0.tgz", + "integrity": "sha512-7zt8tYB6dnSO8fbjUz91MHexGDpf9HrLlA3FAmlVb+2ZL3eWUs499L3I6BDUymcWu7oW5WCBJlB8ERj8ZLLzig==", + "dev": true, + "license": "MIT", + "dependencies": { + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^10.6.0", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@storybook/global": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@storybook/global/-/global-5.0.0.tgz", + "integrity": "sha512-FcOqPAXACP0I3oJ/ws6/rrPT9WGhu915Cg8D02a9YxLo0DE9zI+a9A5gRGvmQ09fiWPukqI8ZAEoQEdWUKMQdQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@storybook/icons": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@storybook/icons/-/icons-2.1.0.tgz", + "integrity": "sha512-Fxh9vYpX9bQqFeHRiY8h2ApeRGDzRSMLwJwNZ/AIRqnyOKHxRKL+yFe+ctEkVJmuptRE9u1Hrn8ZZNHyfDKKNg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/@storybook/react": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/@storybook/react/-/react-10.6.0.tgz", + "integrity": "sha512-0xfYYPRHcr5ta1hmXJCSezH4JGuUHJ+xVF9f1j+Y/MWEMOQE4wnaKWKsk/HLrDjZkT5hKfvmogt9b0yduP6zEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/global": "^5.0.0", + "@storybook/react-dom-shim": "10.6.0", + "react-docgen": "^8.0.2", + "react-docgen-typescript": "^2.2.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "@types/react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "storybook": "^10.6.0", + "typescript": ">= 4.9.x" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/@storybook/react-dom-shim": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/@storybook/react-dom-shim/-/react-dom-shim-10.6.0.tgz", + "integrity": "sha512-ZE0l4xL6d00rKFeJhRDuh0t3r+/2ffhx47lIyaSWrTD5kuM3nDjKDxCIWwX4E3gLV+oNX8E1prXRMuEWJUJwJg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "@types/react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "storybook": "^10.6.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@storybook/react-vite": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/@storybook/react-vite/-/react-vite-10.6.0.tgz", + "integrity": "sha512-nc1dqnmjGOcDJvPCkAn4Hmu1gi7dNHHoibNmlBp0d1adosejELZxuNjHBkPl/KxZjbzP3jljQHnHB/guxd8e2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@joshwooding/vite-plugin-react-docgen-typescript": "^0.7.0", + "@rollup/pluginutils": "^5.0.2", + "@storybook/builder-vite": "10.6.0", + "@storybook/react": "10.6.0", + "empathic": "^2.0.0", + "magic-string": "^1.1.0", + "react-docgen": "^8.0.2", + "resolve": "^1.22.8", + "tsconfig-paths": "^4.2.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "storybook": "^10.6.0", + "typescript": ">= 4.9.x", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@storybook/react-vite/node_modules/magic-string": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-1.2.3.tgz", + "integrity": "sha512-Bpb0W2TbLKOZ7vJnOUnVRGq3WL2p+ISV29M6hYPL1AFCpyKZpdr5ytiXoTSSxRVhg8YW7f65+6gbG8WG6PCa/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, "node_modules/@tailwindcss/node": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.2.2.tgz", @@ -4677,9 +5553,9 @@ } }, "node_modules/@testing-library/user-event": { - "version": "14.6.1", - "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.6.1.tgz", - "integrity": "sha512-vq7fv0rnt+QTXgPxr5Hjc210p6YKq2kmdziLgnsZGgLJ9e6VAShx1pACLuRjd/AS/sr7phAR58OIIpf0LlmQNw==", + "version": "14.6.7", + "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.6.7.tgz", + "integrity": "sha512-MPCpX8bxe8zS+JmmTwLp8jd0dy1rAm60Te/SL8JrQM3qvQJcBOs1d7IefJMyZzqM3EWBrDn/LWDt1BCGu4ASfg==", "dev": true, "license": "MIT", "engines": { @@ -4708,6 +5584,51 @@ "dev": true, "license": "MIT" }, + "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", "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", @@ -4726,6 +5647,13 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/doctrine": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/@types/doctrine/-/doctrine-0.0.9.tgz", + "integrity": "sha512-eOIHzCUSH7SMfonMG1LsC2f8vxBFtho6NGBznK41R84YzPuvSBzrhEps33IsQiOW9+VL6NQ9DbjQJznk/S4uRA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/dom-mediacapture-transform": { "version": "0.1.11", "resolved": "https://registry.npmjs.org/@types/dom-mediacapture-transform/-/dom-mediacapture-transform-0.1.11.tgz", @@ -4777,6 +5705,13 @@ "@types/react": "^19.2.0" } }, + "node_modules/@types/resolve": { + "version": "1.20.6", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.6.tgz", + "integrity": "sha512-A4STmOXPhMUtHH+S6ymgE2GiBSMqf4oTvcQZMcHzokuTLVYzXTB8ttjcgxOVaAp2lGwEdzZ0J+cRbbeevQj1UQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@typescript/typescript-aix-ppc64": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/@typescript/typescript-aix-ppc64/-/typescript-aix-ppc64-7.0.2.tgz", @@ -4784,7 +5719,6 @@ "cpu": [ "ppc64" ], - "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -4801,7 +5735,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -4818,7 +5751,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -4835,7 +5767,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -4852,7 +5783,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -4869,7 +5799,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -4886,7 +5815,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -4903,7 +5831,6 @@ "cpu": [ "loong64" ], - "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -4920,7 +5847,6 @@ "cpu": [ "mips64el" ], - "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -4937,7 +5863,6 @@ "cpu": [ "ppc64" ], - "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -4954,7 +5879,6 @@ "cpu": [ "riscv64" ], - "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -4971,7 +5895,6 @@ "cpu": [ "s390x" ], - "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -4988,7 +5911,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -5005,7 +5927,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -5022,7 +5943,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -5039,7 +5959,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -5056,7 +5975,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -5073,7 +5991,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -5090,7 +6007,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -5107,7 +6023,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -5565,6 +6480,13 @@ "node": ">=20.0.0" } }, + "node_modules/@webcontainer/env": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@webcontainer/env/-/env-1.1.1.tgz", + "integrity": "sha512-6aN99yL695Hi9SuIk1oC88l9o0gmxL1nGWWQ/kNy81HigJ0FoaoTXpytCj6ItzgyCEwA9kF1wixsTuv5cjsgng==", + "dev": true, + "license": "MIT" + }, "node_modules/@webgpu/types": { "version": "0.1.69", "resolved": "https://registry.npmjs.org/@webgpu/types/-/types-0.1.69.tgz", @@ -5673,6 +6595,19 @@ "node": ">=12" } }, + "node_modules/ast-types": { + "version": "0.16.3", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.16.3.tgz", + "integrity": "sha512-FvWoWYfSCM6kRxCSH+MGLHIKKGRL6A6AW7Zek2O32REPQRdg131428uRTKMBYAeRd3XXAaHDS60Wpri7CdKDrA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/ast-v8-to-istanbul": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-1.0.3.tgz", @@ -5705,6 +6640,16 @@ "@babel/types": "^7.23.6" } }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, "node_modules/baseline-browser-mapping": { "version": "2.10.38", "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.38.tgz", @@ -5748,6 +6693,19 @@ "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", "license": "MIT" }, + "node_modules/brace-expansion": { + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz", + "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "20 || >=22" + } + }, "node_modules/braces": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", @@ -5795,6 +6753,22 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/bundle-name": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", + "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "run-applescript": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/caniuse-lite": { "version": "1.0.30001799", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001799.tgz", @@ -5826,6 +6800,16 @@ "node": ">=18" } }, + "node_modules/check-error": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.3.tgz", + "integrity": "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + } + }, "node_modules/chokidar": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", @@ -6032,6 +7016,46 @@ "dev": true, "license": "MIT" }, + "node_modules/deep-eql": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", + "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/default-browser": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.5.1.tgz", + "integrity": "sha512-m1pAzaJgZ/gssEqlOhJkPJp8Xly7QyW6xcrkUa2KKcDeDSEMP7X8xipU3snUcfisTQx0w1AGae+9UtJSfVnXGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.1.tgz", + "integrity": "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/define-data-property": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", @@ -6049,6 +7073,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/define-properties": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", @@ -6107,6 +7144,19 @@ "node": ">=0.3.1" } }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/dom-accessibility-api": { "version": "0.5.16", "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", @@ -6128,6 +7178,16 @@ "dev": true, "license": "MIT" }, + "node_modules/empathic": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/empathic/-/empathic-2.0.1.tgz", + "integrity": "sha512-YGRs8knHhKHVShLkFET/rWAU8kmHbOV5LwN938RHI0pljAJ1Gf6SzXsSmRaEzcXTtOOmVqJ5+WtQPL5uigY50Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + } + }, "node_modules/enhanced-resolve": { "version": "5.20.1", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.20.1.tgz", @@ -6250,6 +7310,20 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "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/estree-walker": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", @@ -6260,6 +7334,16 @@ "@types/estree": "^1.0.0" } }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/expect-type": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.4.0.tgz", @@ -6337,6 +7421,16 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -6388,6 +7482,24 @@ "js-binary-schema-parser": "^2.0.3" } }, + "node_modules/glob": { + "version": "13.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", + "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/glob-parent": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", @@ -6493,6 +7605,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/html-encoding-sniffer": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-6.0.0.tgz", @@ -6619,6 +7744,38 @@ "node": ">=8" } }, + "node_modules/is-core-module": { + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz", + "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "dev": true, + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -6652,6 +7809,25 @@ "node": ">=0.10.0" } }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -6669,6 +7845,22 @@ "dev": true, "license": "MIT" }, + "node_modules/is-wsl": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.1.tgz", + "integrity": "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-inside-container": "^1.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/isbot": { "version": "5.1.38", "resolved": "https://registry.npmjs.org/isbot/-/isbot-5.1.38.tgz", @@ -6812,6 +8004,13 @@ "node": ">=6" } }, + "node_modules/jsonc-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", + "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", + "dev": true, + "license": "MIT" + }, "node_modules/kokoro-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/kokoro-js/-/kokoro-js-1.2.1.tgz", @@ -7144,6 +8343,13 @@ "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", "license": "Apache-2.0" }, + "node_modules/loupe": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz", + "integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==", + "dev": true, + "license": "MIT" + }, "node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -7271,6 +8477,32 @@ "node": ">=4" } }, + "node_modules/minimatch": { + "version": "10.2.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", + "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.8" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/minipass": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", @@ -7438,19 +8670,117 @@ "integrity": "sha512-hHd9n8DzIfGSAjM4Dvslesc8i6h9HEEcl8qt7X3LfhUxMgls6FBJ32j2xrDtJjKJFEehFeJmyB/pvad1I8KS8w==", "license": "MIT", "dependencies": { - "flatbuffers": "^25.1.24", - "guid-typescript": "^1.0.9", - "long": "^5.2.3", - "onnxruntime-common": "1.24.0-dev.20251116-b39e144322", - "platform": "^1.3.6", - "protobufjs": "^7.2.4" + "flatbuffers": "^25.1.24", + "guid-typescript": "^1.0.9", + "long": "^5.2.3", + "onnxruntime-common": "1.24.0-dev.20251116-b39e144322", + "platform": "^1.3.6", + "protobufjs": "^7.2.4" + } + }, + "node_modules/onnxruntime-web/node_modules/onnxruntime-common": { + "version": "1.24.0-dev.20251116-b39e144322", + "resolved": "https://registry.npmjs.org/onnxruntime-common/-/onnxruntime-common-1.24.0-dev.20251116-b39e144322.tgz", + "integrity": "sha512-BOoomdHYmNRL5r4iQ4bMvsl2t0/hzVQ3OM3PHD0gxeXu1PmggqBv3puZicEUVOA3AtHHYmqZtjMj9FOfGrATTw==", + "license": "MIT" + }, + "node_modules/open": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/open/-/open-10.2.0.tgz", + "integrity": "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "default-browser": "^5.2.1", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "wsl-utils": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/oxc-parser": { + "version": "0.127.0", + "resolved": "https://registry.npmjs.org/oxc-parser/-/oxc-parser-0.127.0.tgz", + "integrity": "sha512-bkgD4qHlN7WxLdX8bLXdaU54TtQtAIg/ZBAfm0aje/mo3MRDo3P0hZSgr4U7O3xfX+fQmR5AP04JS/TGcZLcFA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "^0.127.0" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/sponsors/Boshen" + }, + "optionalDependencies": { + "@oxc-parser/binding-android-arm-eabi": "0.127.0", + "@oxc-parser/binding-android-arm64": "0.127.0", + "@oxc-parser/binding-darwin-arm64": "0.127.0", + "@oxc-parser/binding-darwin-x64": "0.127.0", + "@oxc-parser/binding-freebsd-x64": "0.127.0", + "@oxc-parser/binding-linux-arm-gnueabihf": "0.127.0", + "@oxc-parser/binding-linux-arm-musleabihf": "0.127.0", + "@oxc-parser/binding-linux-arm64-gnu": "0.127.0", + "@oxc-parser/binding-linux-arm64-musl": "0.127.0", + "@oxc-parser/binding-linux-ppc64-gnu": "0.127.0", + "@oxc-parser/binding-linux-riscv64-gnu": "0.127.0", + "@oxc-parser/binding-linux-riscv64-musl": "0.127.0", + "@oxc-parser/binding-linux-s390x-gnu": "0.127.0", + "@oxc-parser/binding-linux-x64-gnu": "0.127.0", + "@oxc-parser/binding-linux-x64-musl": "0.127.0", + "@oxc-parser/binding-openharmony-arm64": "0.127.0", + "@oxc-parser/binding-wasm32-wasi": "0.127.0", + "@oxc-parser/binding-win32-arm64-msvc": "0.127.0", + "@oxc-parser/binding-win32-ia32-msvc": "0.127.0", + "@oxc-parser/binding-win32-x64-msvc": "0.127.0" + } + }, + "node_modules/oxc-parser/node_modules/@oxc-project/types": { + "version": "0.127.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.127.0.tgz", + "integrity": "sha512-aIYXQBo4lCbO4z0R3FHeucQHpF46l2LbMdxRvqvuRuW2OxdnSkcng5B8+K12spgLDj93rtN3+J2Vac/TIO+ciQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" } }, - "node_modules/onnxruntime-web/node_modules/onnxruntime-common": { - "version": "1.24.0-dev.20251116-b39e144322", - "resolved": "https://registry.npmjs.org/onnxruntime-common/-/onnxruntime-common-1.24.0-dev.20251116-b39e144322.tgz", - "integrity": "sha512-BOoomdHYmNRL5r4iQ4bMvsl2t0/hzVQ3OM3PHD0gxeXu1PmggqBv3puZicEUVOA3AtHHYmqZtjMj9FOfGrATTw==", - "license": "MIT" + "node_modules/oxc-resolver": { + "version": "11.21.2", + "resolved": "https://registry.npmjs.org/oxc-resolver/-/oxc-resolver-11.21.2.tgz", + "integrity": "sha512-w5tLwYN3Zo24w5EeWJjJWZOwhYqTtC8PS2B1tIt7BZUuqTIcU07sQValbDw+rq7+AuAGzOHklgK+ifsy4lpXfw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + }, + "optionalDependencies": { + "@oxc-resolver/binding-android-arm-eabi": "11.21.2", + "@oxc-resolver/binding-android-arm64": "11.21.2", + "@oxc-resolver/binding-darwin-arm64": "11.21.2", + "@oxc-resolver/binding-darwin-x64": "11.21.2", + "@oxc-resolver/binding-freebsd-x64": "11.21.2", + "@oxc-resolver/binding-linux-arm-gnueabihf": "11.21.2", + "@oxc-resolver/binding-linux-arm-musleabihf": "11.21.2", + "@oxc-resolver/binding-linux-arm64-gnu": "11.21.2", + "@oxc-resolver/binding-linux-arm64-musl": "11.21.2", + "@oxc-resolver/binding-linux-ppc64-gnu": "11.21.2", + "@oxc-resolver/binding-linux-riscv64-gnu": "11.21.2", + "@oxc-resolver/binding-linux-riscv64-musl": "11.21.2", + "@oxc-resolver/binding-linux-s390x-gnu": "11.21.2", + "@oxc-resolver/binding-linux-x64-gnu": "11.21.2", + "@oxc-resolver/binding-linux-x64-musl": "11.21.2", + "@oxc-resolver/binding-openharmony-arm64": "11.21.2", + "@oxc-resolver/binding-wasm32-wasi": "11.21.2", + "@oxc-resolver/binding-win32-arm64-msvc": "11.21.2", + "@oxc-resolver/binding-win32-x64-msvc": "11.21.2" + } }, "node_modules/oxfmt": { "version": "0.57.0", @@ -7584,6 +8914,40 @@ "url": "https://github.com/inikulin/parse5?sponsor=1" } }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-scurry": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "11.5.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.2.tgz", + "integrity": "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, "node_modules/pathe": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", @@ -7591,6 +8955,16 @@ "dev": true, "license": "MIT" }, + "node_modules/pathval": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz", + "integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.16" + } + }, "node_modules/phonemizer": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/phonemizer/-/phonemizer-1.2.1.tgz", @@ -7805,6 +9179,51 @@ "react-dom": ">=16.8.0" } }, + "node_modules/react-docgen": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/react-docgen/-/react-docgen-8.0.3.tgz", + "integrity": "sha512-aEZ9qP+/M+58x2qgfSFEWH1BxLyHe5+qkLNJOZQb5iGS017jpbRnoKhNRrXPeA6RfBrZO5wZrT9DMC1UqE1f1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.28.0", + "@babel/traverse": "^7.28.0", + "@babel/types": "^7.28.2", + "@types/babel__core": "^7.20.5", + "@types/babel__traverse": "^7.20.7", + "@types/doctrine": "^0.0.9", + "@types/resolve": "^1.20.2", + "doctrine": "^3.0.0", + "resolve": "^1.22.1", + "strip-indent": "^4.0.0" + }, + "engines": { + "node": "^20.9.0 || >=22" + } + }, + "node_modules/react-docgen-typescript": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/react-docgen-typescript/-/react-docgen-typescript-2.4.0.tgz", + "integrity": "sha512-ZtAp5XTO5HRzQctjPU0ybY0RRCQO19X/8fxn3w7y2VVTUbGHDKULPTL4ky3vB05euSgG5NpALhEhDPvQ56wvXg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "typescript": ">= 4.3.x" + } + }, + "node_modules/react-docgen/node_modules/strip-indent": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-4.1.1.tgz", + "integrity": "sha512-SlyRoSkdh1dYP0PzclLE7r0M9sgbFKKMFXpFRUMNuKhQSbC6VQIGzq3E0qsfvGJaUFJPGv6Ws1NZ/haTAjfbMA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/react-dom": { "version": "19.2.5", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.5.tgz", @@ -7969,6 +9388,23 @@ "node": ">=8.10.0" } }, + "node_modules/recast": { + "version": "0.23.21", + "resolved": "https://registry.npmjs.org/recast/-/recast-0.23.21.tgz", + "integrity": "sha512-mFAyJq9vUbSTARLZUvAEf1z3YxlvAwswbmxMx2mPA/MSm4KmpwvwvhsH/NIrZhyOuwD60Lzyw2qh83uCbgTPYw==", + "dev": true, + "license": "MIT", + "dependencies": { + "ast-types": "^0.16.1", + "esprima": "~4.0.0", + "source-map": "~0.6.1", + "tiny-invariant": "^1.3.3", + "tslib": "^2.0.1" + }, + "engines": { + "node": ">= 4" + } + }, "node_modules/redent": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", @@ -8003,6 +9439,28 @@ "node": ">=0.10.0" } }, + "node_modules/resolve": { + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/resolve-pkg-maps": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", @@ -8071,6 +9529,19 @@ "dev": true, "license": "MIT" }, + "node_modules/run-applescript": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz", + "integrity": "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/saxes": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", @@ -8230,6 +9701,16 @@ "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-rc" } }, + "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", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -8260,6 +9741,153 @@ "dev": true, "license": "MIT" }, + "node_modules/storybook": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/storybook/-/storybook-10.6.0.tgz", + "integrity": "sha512-H48X6AURAFTpfN2zEux6vNesee5Oq8Gxj1IanYmblPZ218sfKSeyyerF1NC7GD7BrruoC8L4/cU0zII4y+d6zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/global": "^5.0.0", + "@storybook/icons": "^2.0.2", + "@testing-library/dom": "^10.4.1", + "@testing-library/jest-dom": "6.9.1", + "@testing-library/user-event": "^14.6.3", + "@vitest/expect": "3.2.4", + "@vitest/spy": "3.2.4", + "@webcontainer/env": "^1.1.1", + "esbuild": "^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0 || ^0.25.0 || ^0.26.0 || ^0.27.0 || ^0.28.0", + "jsonc-parser": "^3.3.1", + "open": "^10.2.0", + "oxc-parser": "^0.127.0", + "oxc-resolver": "11.21.2", + "recast": "^0.23.5", + "semver": "^7.7.3", + "use-sync-external-store": "^1.5.0", + "ws": "^8.21.1" + }, + "bin": { + "storybook": "dist/bin/dispatcher.js" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "prettier": "^2 || ^3", + "vite-plus": "^0.1.15 || ^0.2.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "prettier": { + "optional": true + }, + "vite-plus": { + "optional": true + } + } + }, + "node_modules/storybook/node_modules/@vitest/expect": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.4.tgz", + "integrity": "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "^5.2.2", + "@vitest/spy": "3.2.4", + "@vitest/utils": "3.2.4", + "chai": "^5.2.0", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/storybook/node_modules/@vitest/pretty-format": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.4.tgz", + "integrity": "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/storybook/node_modules/@vitest/spy": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.4.tgz", + "integrity": "sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyspy": "^4.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/storybook/node_modules/@vitest/utils": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.4.tgz", + "integrity": "sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "3.2.4", + "loupe": "^3.1.4", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/storybook/node_modules/chai": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.3.3.tgz", + "integrity": "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "assertion-error": "^2.0.1", + "check-error": "^2.1.1", + "deep-eql": "^5.0.1", + "loupe": "^3.1.0", + "pathval": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/storybook/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/storybook/node_modules/tinyrainbow": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz", + "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -8288,6 +9916,16 @@ "node": ">=8" } }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/strip-indent": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", @@ -8314,6 +9952,19 @@ "node": ">=8" } }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/symbol-tree": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", @@ -8385,6 +10036,13 @@ "node": ">=18" } }, + "node_modules/tiny-invariant": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", + "dev": true, + "license": "MIT" + }, "node_modules/tinybench": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", @@ -8470,6 +10128,16 @@ "node": ">=14.0.0" } }, + "node_modules/tinyspy": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-4.0.6.tgz", + "integrity": "sha512-u8KszXvGfU68hVcZpRHKG28T0krMuv2G5nDhiHaMLen/gIuFEgIJhaJuO69qjnXg5paSrbPMFfx3brNuN8eVSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/tldts": { "version": "7.0.28", "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.0.28.tgz", @@ -8539,6 +10207,31 @@ "node": ">=20" } }, + "node_modules/ts-dedent": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/ts-dedent/-/ts-dedent-2.3.0.tgz", + "integrity": "sha512-JfJeIHke7y2egdGGgRAvpCwYFUsHlM2gPcrVOxFkznt/4uzQ7HFmvE63iFHVLBJNDuyDOQgijDK/tXH/f6Msjg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.10" + } + }, + "node_modules/tsconfig-paths": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", + "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "json5": "^2.2.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", @@ -9066,9 +10759,9 @@ } }, "node_modules/ws": { - "version": "8.21.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", - "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", + "version": "8.21.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.3.tgz", + "integrity": "sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==", "dev": true, "license": "MIT", "engines": { @@ -9087,6 +10780,22 @@ } } }, + "node_modules/wsl-utils": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.1.0.tgz", + "integrity": "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-wsl": "^3.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/xml-name-validator": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", diff --git a/package.json b/package.json index 9600ad50c..ede5929d7 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,8 @@ "preview": "vp preview", "preview:perf": "vp preview --host --strictPort --port 4173", "perf": "vp run build:perf && vp run preview:perf", + "storybook": "storybook dev -p 6006 --no-open", + "build:storybook": "storybook build", "routes": "tsr generate", "test": "vp test", "test:run": "vp test run", @@ -118,6 +120,7 @@ "zustand": "5.0.12" }, "devDependencies": { + "@storybook/react-vite": "10.6.0", "@tailwindcss/vite": "4.2.2", "@tanstack/router-cli": "1.166.33", "@testing-library/dom": "10.4.1", @@ -131,6 +134,7 @@ "@webgpu/types": "0.1.69", "jsdom": "27.4.0", "playwright": "1.60.0", + "storybook": "10.6.0", "tailwindcss": "4.2.2", "typescript": "7.0.2", "vite-plus": "0.2.4" diff --git a/provenance/dependency-inventory.json b/provenance/dependency-inventory.json index c08f6d559..9846c5c7a 100644 --- a/provenance/dependency-inventory.json +++ b/provenance/dependency-inventory.json @@ -3,11 +3,11 @@ "generatedFrom": "package.json", "packageName": "freecut", "packageVersion": "0.0.0", - "packageJsonSha256": "7786ffe5cde5b09b6f88fc4fd13af399365ac0d6dc32f320d6f719c6f62edc89", + "packageJsonSha256": "c40bf894a34dc7677f6c45979775ee3987c8dcd57fd8498126bd0b4f7e7c4bbe", "lockfile": { "path": "package-lock.json", "lockfileVersion": 3, - "sha256": "b4a86741ce7891da1f63df01b6fdd4ed507e8887d5097c6a0f93fc2ea6f3420e" + "sha256": "5dcdd7fe99c39fd6d7e4eb90d87dc1817b631392d66d163cf1c9695cc6c7b363" }, "directDependencies": { "dependencies": { @@ -64,6 +64,7 @@ "zustand": "5.0.12" }, "devDependencies": { + "@storybook/react-vite": "10.6.0", "@tailwindcss/vite": "4.2.2", "@tanstack/router-cli": "1.166.33", "@testing-library/dom": "10.4.1", @@ -77,6 +78,7 @@ "@webgpu/types": "0.1.69", "jsdom": "27.4.0", "playwright": "1.60.0", + "storybook": "10.6.0", "tailwindcss": "4.2.2", "typescript": "7.0.2", "vite-plus": "0.2.4" diff --git a/provenance/freecut-baseline.json b/provenance/freecut-baseline.json index 3ee69326d..7ca99210e 100644 --- a/provenance/freecut-baseline.json +++ b/provenance/freecut-baseline.json @@ -34,10 +34,10 @@ ], "dependencies": { "packageJson": "package.json", - "packageJsonSha256": "7786ffe5cde5b09b6f88fc4fd13af399365ac0d6dc32f320d6f719c6f62edc89", + "packageJsonSha256": "c40bf894a34dc7677f6c45979775ee3987c8dcd57fd8498126bd0b4f7e7c4bbe", "lockfile": "package-lock.json", "lockfileVersion": 3, - "lockfileSha256": "b4a86741ce7891da1f63df01b6fdd4ed507e8887d5097c6a0f93fc2ea6f3420e", + "lockfileSha256": "5dcdd7fe99c39fd6d7e4eb90d87dc1817b631392d66d163cf1c9695cc6c7b363", "inventory": "provenance/dependency-inventory.json" }, "assets": { diff --git a/src/components/brand/discord-icon.stories.tsx b/src/components/brand/discord-icon.stories.tsx new file mode 100644 index 000000000..429b5832c --- /dev/null +++ b/src/components/brand/discord-icon.stories.tsx @@ -0,0 +1,42 @@ +import type { Meta, StoryObj } from '@storybook/react-vite' +import { DiscordIcon } from '@/components/brand/discord-icon' +import { Button } from '@/components/ui/button' + +const meta = { + title: 'Brand/DiscordIcon', + component: DiscordIcon, +} satisfies Meta + +export default meta + +type Story = StoryObj + +/** Lucide ships no Discord glyph, so the official mark is inlined. It paints in + * `currentColor`, so it inherits text colour exactly like a lucide icon. */ +export const Default: Story = { + render: (args) => , +} + +export const Sizes: Story = { + render: () => ( +
+ {['h-4 w-4', 'h-5 w-5', 'h-6 w-6', 'h-8 w-8'].map((size) => ( + + ))} +
+ ), +} + +export const InButton: Story = { + render: () => ( +
+ + +
+ ), +} diff --git a/src/components/brand/freecut-logo.stories.tsx b/src/components/brand/freecut-logo.stories.tsx new file mode 100644 index 000000000..fcf981752 --- /dev/null +++ b/src/components/brand/freecut-logo.stories.tsx @@ -0,0 +1,44 @@ +import type { Meta, StoryObj } from '@storybook/react-vite' +import { FreeCutLogo } from '@/components/brand/freecut-logo' + +const meta = { + title: 'Brand/FreeCutLogo', + component: FreeCutLogo, + argTypes: { + variant: { control: 'inline-radio', options: ['full', 'icon'] }, + size: { control: 'inline-radio', options: ['sm', 'md', 'lg'] }, + }, +} satisfies Meta + +export default meta + +type Story = StoryObj + +export const Full: Story = { args: { variant: 'full', size: 'md' } } + +export const Icon: Story = { args: { variant: 'icon', size: 'md' } } + +export const Sizes: Story = { + render: () => ( +
+ {(['sm', 'md', 'lg'] as const).map((size) => ( +
+ + + {size} + +
+ ))} +
+ ), +} + +/** The mark takes the signal orange; the wordmark stays ink. */ +export const OnPanel: Story = { + render: () => ( +
+ + v0.0.0 +
+ ), +} diff --git a/src/components/foundations.stories.tsx b/src/components/foundations.stories.tsx new file mode 100644 index 000000000..25f260bf9 --- /dev/null +++ b/src/components/foundations.stories.tsx @@ -0,0 +1,305 @@ +import { useEffect, useState, type ReactNode } from 'react' +import type { Meta, StoryObj } from '@storybook/react-vite' + +/** + * The design language itself — colour ramp, type scale, spacing, radii, + * elevation and easing — read live out of `src/index.css` and the timeline + * theme extension, so this page cannot drift from the tokens the app ships. + */ +const meta = { + title: 'Foundations/Design Tokens', + parameters: { layout: 'fullscreen' }, +} satisfies Meta + +export default meta + +type Story = StoryObj + +/** Resolves a custom property off `:root` so swatches show the real value. */ +function useTokenValue(token: string): string { + const [value, setValue] = useState('') + + useEffect(() => { + const resolved = getComputedStyle(document.documentElement).getPropertyValue(token).trim() + setValue(resolved) + }, [token]) + + return value +} + +function Section({ title, hint, children }: { title: string; hint?: string; children: ReactNode }) { + return ( +
+
+

{title}

+ {hint &&

{hint}

} +
+ {children} +
+ ) +} + +function Swatch({ token, name, note }: { token: string; name: string; note?: string }) { + const value = useTokenValue(token) + + return ( +
+ + + {name} + {token} + + {value || '—'} + + {note && {note}} + +
+ ) +} + +function SwatchGrid({ children }: { children: ReactNode }) { + return
{children}
+} + +/** + * A near-monochrome graphite ramp lit by a single warm orange. Depth comes from + * stepping lightness, not from shadows — the timeline floor is darkest, panels + * sit above it, popovers in between. + */ +export const Colors: Story = { + render: () => ( +
+
+ + + + + +
+ +
+ + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + + + + + + + + + +
+
+ ), +} + +const typeScale = [ + { name: 'Headline', className: 'text-xl font-semibold tracking-tight', role: 'Dialog titles' }, + { name: 'Title', className: 'text-base font-semibold', role: 'Panel titles' }, + { name: 'Body', className: 'text-sm', role: 'Default UI text, menu items' }, + { name: 'Label', className: 'text-xs font-medium', role: 'Control labels, captions' }, + { + name: 'Mono', + className: 'font-mono text-xs tabular-nums', + role: 'Timecode, frames, fps, dB', + }, +] + +/** + * IBM Plex Sans does the interface work; IBM Plex Mono takes every value an + * editor reads precisely, so digits align and never jump width. + */ +export const Typography: Story = { + render: () => ( +
+
+
+ {typeScale.map((step) => ( +
+
+ + {step.name} + + {step.role} +
+

Ripple delete closes the gap — 00:01:12:04

+
+ ))} +
+
+ +
+
+
+

Mono, tabular

+

00:00:04:11

+

00:01:12:04

+

23.976 fps · −6.0 dB

+
+
+

Sans — digits drift

+

00:00:04:11

+

00:01:12:04

+

23.976 fps · −6.0 dB

+
+
+
+
+ ), +} + +const spacingSteps = [ + { name: 'xs', className: 'w-1', px: '4px' }, + { name: 'sm', className: 'w-2', px: '8px' }, + { name: 'md', className: 'w-3', px: '12px' }, + { name: 'lg', className: 'w-4', px: '16px' }, + { name: 'xl', className: 'w-6', px: '24px' }, +] + +const radiusSteps = [ + { name: 'sm', token: '--radius-sm', className: 'rounded-sm' }, + { name: 'md', token: '--radius-md', className: 'rounded-md' }, + { name: 'lg', token: '--radius-lg', className: 'rounded-lg' }, + { name: 'xl', token: '--radius-xl', className: 'rounded-xl' }, +] + +export const SpacingAndRadii: Story = { + render: () => ( +
+
+
+ {spacingSteps.map((step) => ( +
+ {step.name} + + {step.px} +
+ ))} +
+
+ +
+
+ {radiusSteps.map((step) => ( +
+ + {step.name} +
+ ))} +
+
+
+ ), +} + +/** + * Flat by default. Panels are separated by value, not lift; shadows are for + * things that genuinely float, plus the orange glow on active elements. + */ +export const Elevation: Story = { + render: () => ( +
+
+

Flat panel

+

Default. No shadow.

+
+
+

Floating layer

+

Menus, popovers, dialogs.

+
+
+

Signal glow

+

Active / playing elements only.

+
+
+ ), +} + +const easings = [ + { token: '--ease-out-strong', name: 'ease-out-strong', role: 'UI entrances and exits' }, + { token: '--ease-in-out-strong', name: 'ease-in-out-strong', role: 'On-screen movement' }, + { token: '--ease-drawer', name: 'ease-drawer', role: 'Drawer and panel slides' }, +] + +/** Shared curves — reference these instead of hand-rolling cubic-beziers. */ +export const Motion: Story = { + render: function MotionStory() { + const [shifted, setShifted] = useState(false) + + return ( +
+ +
+ {easings.map((easing) => ( +
+
+ {easing.name} + {easing.role} +
+
+ +
+
+ ))} +
+
+ ) + }, +} diff --git a/src/components/ui/accordion.stories.tsx b/src/components/ui/accordion.stories.tsx new file mode 100644 index 000000000..6e0464541 --- /dev/null +++ b/src/components/ui/accordion.stories.tsx @@ -0,0 +1,79 @@ +import type { Meta, StoryObj } from '@storybook/react-vite' +import { + Accordion, + AccordionContent, + AccordionItem, + AccordionTrigger, +} from '@/components/ui/accordion' + +const meta = { + title: 'UI/Accordion', + component: Accordion, +} satisfies Meta + +export default meta + +type Story = StoryObj + +export const Single: Story = { + args: { type: 'single', collapsible: true, defaultValue: 'transform' }, + render: (args) => ( + + + Transform + + Position, scale, rotation and anchor point. + + + + Opacity + + Blend mode and opacity keyframes. + + + + Speed / duration + + Rate, reverse and frame blending. + + + + ), +} + +export const Multiple: Story = { + args: { type: 'multiple', defaultValue: ['transform', 'opacity'] }, + render: (args) => ( + + + Transform + + Position, scale, rotation and anchor point. + + + + Opacity + + Blend mode and opacity keyframes. + + + + ), +} + +/** A long body wraps inside the panel width rather than widening it. */ +export const LongContent: Story = { + args: { type: 'single', collapsible: true, defaultValue: 'about' }, + render: (args) => ( + + + About frame blending + + Frame blending interpolates between source frames when a clip is retimed, which smooths + slow motion at the cost of render time. Optical flow produces the cleanest result but is + the slowest of the three modes, so it is usually left off until the final export. + + + + ), +} diff --git a/src/components/ui/alert-dialog.stories.tsx b/src/components/ui/alert-dialog.stories.tsx new file mode 100644 index 000000000..89b26a026 --- /dev/null +++ b/src/components/ui/alert-dialog.stories.tsx @@ -0,0 +1,63 @@ +import type { Meta, StoryObj } from '@storybook/react-vite' +import { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, +} from '@/components/ui/alert-dialog' + +const meta = { + title: 'UI/AlertDialog', + component: AlertDialog, +} satisfies Meta + +export default meta + +type Story = StoryObj + +/** Confirmation for a destructive, unqueued action — no close X, an explicit cancel. */ +export const Destructive: Story = { + args: { defaultOpen: true }, + render: (args) => ( + + + + Delete 3 clips? + + The clips are removed from the timeline. The source media on disk is untouched. + + + + Cancel + Delete + + + + ), +} + +export const LongDescription: Story = { + args: { defaultOpen: true }, + render: (args) => ( + + + + Bake motion into keyframes? + + Baking converts the generated motion into explicit keyframes on the clip. You can edit + each keyframe afterwards, but the generator's parameters are no longer live — changing + them will not update this clip. Undo restores the generated motion. + + + + Cancel + Bake + + + + ), +} diff --git a/src/components/ui/alert.stories.tsx b/src/components/ui/alert.stories.tsx new file mode 100644 index 000000000..05e955987 --- /dev/null +++ b/src/components/ui/alert.stories.tsx @@ -0,0 +1,59 @@ +import type { Meta, StoryObj } from '@storybook/react-vite' +import { AlertTriangle, Info } from 'lucide-react' +import { Alert, AlertDescription } from '@/components/ui/alert' + +const meta = { + title: 'UI/Alert', + component: Alert, + argTypes: { variant: { control: 'inline-radio', options: ['default', 'destructive'] } }, +} satisfies Meta + +export default meta + +type Story = StoryObj + +export const Default: Story = { + render: (args) => ( + + + + Proxy media is generated in the background. The timeline stays editable while it runs. + + + ), +} + +export const Destructive: Story = { + args: { variant: 'destructive' }, + render: (args) => ( + + + + This clip's source file is offline. Relink it before exporting. + + + ), +} + +/** Without an icon the description fills the full width — no left gutter. */ +export const WithoutIcon: Story = { + render: (args) => ( + + Autosave is on. Your project is saved locally. + + ), +} + +export const LongContent: Story = { + args: { variant: 'destructive' }, + render: (args) => ( + + + + Hardware encoding is unavailable in this browser, so the export fell back to a software + encoder. Renders will take noticeably longer, and very long sequences may exceed the + available memory. Try a Chromium-based browser for hardware acceleration. + + + ), +} diff --git a/src/components/ui/button.stories.tsx b/src/components/ui/button.stories.tsx new file mode 100644 index 000000000..5554d2c45 --- /dev/null +++ b/src/components/ui/button.stories.tsx @@ -0,0 +1,118 @@ +import type { Meta, StoryObj } from '@storybook/react-vite' +import { Loader2, Play, Scissors, Trash2 } from 'lucide-react' +import { Button } from '@/components/ui/button' + +const meta = { + title: 'UI/Button', + component: Button, + argTypes: { + variant: { + control: 'select', + options: ['default', 'destructive', 'outline', 'secondary', 'ghost', 'link'], + }, + size: { control: 'select', options: ['default', 'sm', 'lg', 'icon'] }, + disabled: { control: 'boolean' }, + }, + args: { children: 'Export' }, +} satisfies Meta + +export default meta + +type Story = StoryObj + +export const Default: Story = {} + +export const Variants: Story = { + render: (args) => ( +
+ + + + + + +
+ ), +} + +export const Sizes: Story = { + render: (args) => ( +
+ + + + +
+ ), +} + +export const WithIcon: Story = { + args: { + children: ( + <> + + Play from in point + + ), + }, +} + +export const Disabled: Story = { + render: (args) => ( +
+ + + +
+ ), +} + +export const Loading: Story = { + args: { + disabled: true, + children: ( + <> + + Rendering… + + ), + }, +} + +/** Long labels must not wrap — the toolbar relies on `whitespace-nowrap`. */ +export const LongLabel: Story = { + render: (args) => ( +
+ +
+ ), +} diff --git a/src/components/ui/collapsible.stories.tsx b/src/components/ui/collapsible.stories.tsx new file mode 100644 index 000000000..b04bccd26 --- /dev/null +++ b/src/components/ui/collapsible.stories.tsx @@ -0,0 +1,37 @@ +import type { Meta, StoryObj } from '@storybook/react-vite' +import { ChevronRight } from 'lucide-react' +import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible' + +const meta = { + title: 'UI/Collapsible', + component: Collapsible, +} satisfies Meta + +export default meta + +type Story = StoryObj + +/** + * The unstyled Radix primitive — panels wrap it with their own chrome (see + * Property Controls / PropertySection for the editor's styled use). + */ +export const Default: Story = { + args: { defaultOpen: true }, + render: (args) => ( + + + + Audio channels + + +

L −6.0 dB

+

R −6.0 dB

+
+
+ ), +} + +export const Closed: Story = { + args: { defaultOpen: false }, + render: Default.render, +} diff --git a/src/components/ui/combobox.stories.tsx b/src/components/ui/combobox.stories.tsx new file mode 100644 index 000000000..357e4d484 --- /dev/null +++ b/src/components/ui/combobox.stories.tsx @@ -0,0 +1,66 @@ +import { useState, type ComponentProps } from 'react' +import type { Meta, StoryObj } from '@storybook/react-vite' +import { Combobox } from '@/components/ui/combobox' +import { Label } from '@/components/ui/label' + +const fonts = [ + { value: 'ibm-plex-sans', label: 'IBM Plex Sans', keywords: ['plex', 'sans'] }, + { value: 'ibm-plex-mono', label: 'IBM Plex Mono', keywords: ['plex', 'mono', 'code'] }, + { value: 'inter', label: 'Inter' }, + { value: 'source-serif', label: 'Source Serif 4', keywords: ['serif'] }, + { value: 'jetbrains-mono', label: 'JetBrains Mono', keywords: ['mono', 'code'] }, + { value: 'space-grotesk', label: 'Space Grotesk' }, + { value: 'work-sans', label: 'Work Sans' }, + { value: 'dm-serif-display', label: 'DM Serif Display', keywords: ['serif', 'display'] }, +] + +const meta = { + title: 'UI/Combobox', + component: Combobox, + args: { + options: fonts, + placeholder: 'Select a font', + searchPlaceholder: 'Search fonts…', + value: '', + onValueChange: () => undefined, + }, +} satisfies Meta + +export default meta + +type Story = StoryObj + +function ControlledCombobox({ + initialValue = '', + ...args +}: Omit, 'value' | 'onValueChange'> & { + initialValue?: string +}) { + const [value, setValue] = useState(initialValue) + return ( +
+ + +
+ ) +} + +/** A searchable select: filters on label, value and the optional `keywords`. */ +export const Default: Story = { + render: (args) => , +} + +export const WithSelection: Story = { + render: (args) => , +} + +export const Disabled: Story = { + args: { disabled: true }, + render: (args) => , +} + +/** The empty message shows when nothing matches the query. */ +export const NoOptions: Story = { + args: { options: [], emptyMessage: 'No fonts installed.' }, + render: (args) => , +} diff --git a/src/components/ui/context-menu.stories.tsx b/src/components/ui/context-menu.stories.tsx new file mode 100644 index 000000000..ef6e9d709 --- /dev/null +++ b/src/components/ui/context-menu.stories.tsx @@ -0,0 +1,92 @@ +import type { Meta, StoryObj } from '@storybook/react-vite' +import { + ContextMenu, + ContextMenuContent, + ContextMenuItem, + ContextMenuLabel, + ContextMenuSeparator, + ContextMenuShortcut, + ContextMenuSub, + ContextMenuSubContent, + ContextMenuSubTrigger, + ContextMenuTrigger, +} from '@/components/ui/context-menu' + +const meta = { + title: 'UI/ContextMenu', + component: ContextMenu, +} satisfies Meta + +export default meta + +type Story = StoryObj + +/** Right-click the clip below — this is the timeline's clip menu. */ +export const ClipMenu: Story = { + render: (args) => ( + + +
+ A001_C003.mov +
+
+ + Clip + + Cut + ⌘X + + + Copy + ⌘C + + + + Split at playhead + S + + + Speed + + 50% + 100% + 200% + + + + + Ripple delete + ⇧⌫ + + Reveal in Finder (desktop only) + +
+ ), +} + +/** Disabled and shortcut-bearing items, on the media-bin row menu. */ +export const MediaBinMenu: Story = { + render: (args) => ( + + +
+ voiceover-take-4.wav + 00:01:12:04 +
+
+ + + Insert at playhead + , + + + Overwrite at playhead + . + + + Rename… + Reveal in Finder (desktop only) + +
+ ), +} diff --git a/src/components/ui/dialog.stories.tsx b/src/components/ui/dialog.stories.tsx new file mode 100644 index 000000000..3b4ba0165 --- /dev/null +++ b/src/components/ui/dialog.stories.tsx @@ -0,0 +1,126 @@ +import { useState } from 'react' +import type { Meta, StoryObj } from '@storybook/react-vite' +import { Button } from '@/components/ui/button' +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, +} from '@/components/ui/dialog' +import { Input } from '@/components/ui/input' +import { Label } from '@/components/ui/label' +import { Progress } from '@/components/ui/progress' + +const meta = { + title: 'UI/Dialog', + component: Dialog, +} satisfies Meta + +export default meta + +type Story = StoryObj + +export const Default: Story = { + args: { defaultOpen: true }, + render: (args) => ( + + + + Export sequence + + Renders the full timeline. You can keep editing while it runs. + + +
+ + +
+ + + + +
+
+ ), +} + +/** Progress dialogs hide the close affordance so a render is not dismissed by accident. */ +export const WithoutCloseButton: Story = { + args: { defaultOpen: true }, + render: (args) => ( + + + + Rendering + Frame 1 728 of 2 400 + + + + + + + + ), +} + +export const LongContent: Story = { + args: { defaultOpen: true }, + render: (args) => ( + + + + Relink offline media + + Four clips point at files that are no longer readable. Relinking asks for the folder + they moved to and rewrites every reference in the project, including clips nested inside + compositions. Nothing is re-encoded, and the edit is left untouched — only the path each + clip resolves through changes. + + +
    +
  • A001_C003.mov
  • +
  • A001_C007.mov
  • +
  • A002_C001.mov
  • +
  • voiceover-take-4.wav
  • +
+ + + + +
+
+ ), +} + +/** + * `ui/dialog` deliberately exports no `DialogTrigger` — every caller in the editor + * drives `open` from its own store, so the controlled shape is the real one. + */ +export const Controlled: Story = { + render: function ControlledDialog() { + const [open, setOpen] = useState(false) + return ( + <> + + + + + Project settings + Resolution, frame rate and colour space. + + + + + + + + + ) + }, +} diff --git a/src/components/ui/dropdown-menu.stories.tsx b/src/components/ui/dropdown-menu.stories.tsx new file mode 100644 index 000000000..306bf9be6 --- /dev/null +++ b/src/components/ui/dropdown-menu.stories.tsx @@ -0,0 +1,98 @@ +import type { Meta, StoryObj } from '@storybook/react-vite' +import { Download, FileVideo, FolderOpen, Save, Settings } from 'lucide-react' +import { Button } from '@/components/ui/button' +import { + DropdownMenu, + DropdownMenuCheckboxItem, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from '@/components/ui/dropdown-menu' + +const meta = { + title: 'UI/DropdownMenu', + component: DropdownMenu, +} satisfies Meta + +export default meta + +type Story = StoryObj + +export const Default: Story = { + args: { defaultOpen: true }, + render: (args) => ( +
+ + + + + + Project + + + Open project… + + + + Save + + + + + Import media… + + + + Export… + + + + + Preferences (desktop only) + + + +
+ ), +} + +export const WithCheckboxItems: Story = { + args: { defaultOpen: true }, + render: (args) => ( +
+ + + + + + Timeline + Show audio waveforms + Show snapping guides + Show frame numbers + + +
+ ), +} + +/** `inset` reserves the indicator gutter so plain items line up under checkable ones. */ +export const InsetItems: Story = { + args: { defaultOpen: true }, + render: (args) => ( +
+ + + + + + Lock track + + Add track above + Add track below + + +
+ ), +} diff --git a/src/components/ui/floating-panel.stories.tsx b/src/components/ui/floating-panel.stories.tsx new file mode 100644 index 000000000..31ac55090 --- /dev/null +++ b/src/components/ui/floating-panel.stories.tsx @@ -0,0 +1,79 @@ +import type { Meta, StoryObj } from '@storybook/react-vite' +import { Pin } from 'lucide-react' +import { Button } from '@/components/ui/button' +import { FloatingPanel } from '@/components/ui/floating-panel' + +const meta = { + title: 'UI/FloatingPanel', + component: FloatingPanel, + args: { defaultBounds: { x: 120, y: 120, width: 320, height: 260 }, children: null }, +} satisfies Meta + +export default meta + +type Story = StoryObj + +/** + * A draggable, resizable panel portalled to `document.body` — used for detached + * scopes and inspectors. Drag the header, or pull any edge or corner to resize. + * No `storageKey` here, so each story starts from `defaultBounds` instead of + * restoring a persisted position. + */ +export const Default: Story = { + render: (args) => ( + +
+

Waveform, vectorscope and histogram for the current frame.

+

Y 0.18 — 0.92

+
+
+ ), +} + +export const WithHeaderAction: Story = { + render: (args) => ( + + + + } + onClose={() => undefined} + > +
+

L −6.0 dB

+

R −6.4 dB

+
+
+ ), +} + +/** `autoHeight` lets the body set the height; resizing is off for these. */ +export const AutoHeight: Story = { + args: { + defaultBounds: { x: 480, y: 120, width: 260, height: 0 }, + autoHeight: true, + resizable: false, + }, + render: (args) => ( + +
+

Snap to clip edges

+

Snap to playhead

+

Snap to markers

+
+
+ ), +} + +/** Untitled panels drop the header text but keep the drag surface. */ +export const Untitled: Story = { + args: { defaultBounds: { x: 120, y: 420, width: 260, height: 180 } }, + render: (args) => ( + +
No title — the bar is the grip.
+
+ ), +} diff --git a/src/components/ui/global-tooltip.stories.tsx b/src/components/ui/global-tooltip.stories.tsx new file mode 100644 index 000000000..e77ee5093 --- /dev/null +++ b/src/components/ui/global-tooltip.stories.tsx @@ -0,0 +1,69 @@ +import type { Meta, StoryObj } from '@storybook/react-vite' +import { Magnet, Redo2, Scissors, Undo2 } from 'lucide-react' +import { Button } from '@/components/ui/button' +import { GlobalTooltip } from '@/components/ui/global-tooltip' + +const meta = { + title: 'UI/GlobalTooltip', + component: GlobalTooltip, +} satisfies Meta + +export default meta + +type Story = StoryObj + +/** + * One tooltip instance for the whole app: it listens for hover on any element + * carrying `data-tooltip` instead of mounting a Radix tooltip per button, which + * is what keeps a dense toolbar cheap. Hover the buttons below to see it — the + * first opens after 300 ms, and moving straight to a neighbour opens instantly. + */ +export const ToolbarHover: Story = { + render: () => ( + <> + +
+ + + + +
+ + ), +} + +/** `data-tooltip-side` picks the side per trigger. */ +export const Sides: Story = { + render: () => ( + <> + +
+ {(['top', 'right', 'bottom', 'left'] as const).map((side) => ( + + ))} +
+ + ), +} diff --git a/src/components/ui/input.stories.tsx b/src/components/ui/input.stories.tsx new file mode 100644 index 000000000..f52f2bcf1 --- /dev/null +++ b/src/components/ui/input.stories.tsx @@ -0,0 +1,58 @@ +import type { Meta, StoryObj } from '@storybook/react-vite' +import { Input } from '@/components/ui/input' +import { Label } from '@/components/ui/label' + +const meta = { + title: 'UI/Input', + component: Input, + args: { placeholder: 'Sequence name' }, + argTypes: { + type: { control: 'select', options: ['text', 'number', 'search', 'file'] }, + disabled: { control: 'boolean' }, + }, +} satisfies Meta + +export default meta + +type Story = StoryObj + +export const Default: Story = { + render: (args) => , +} + +export const WithLabel: Story = { + render: (args) => ( +
+ + +
+ ), +} + +export const Filled: Story = { + args: { defaultValue: 'Interview — cut 03' }, + render: (args) => , +} + +/** Frame counts and durations are read precisely, so numeric fields go mono. */ +export const Numeric: Story = { + args: { type: 'number', defaultValue: 1920 }, + render: (args) => ( +
+ + +
+ ), +} + +export const Disabled: Story = { + args: { disabled: true, defaultValue: 'Locked while rendering' }, + render: (args) => , +} + +export const FileInput: Story = { + args: { type: 'file' }, + render: (args) => , +} diff --git a/src/components/ui/label.stories.tsx b/src/components/ui/label.stories.tsx new file mode 100644 index 000000000..9b2d2f8c0 --- /dev/null +++ b/src/components/ui/label.stories.tsx @@ -0,0 +1,38 @@ +import type { Meta, StoryObj } from '@storybook/react-vite' +import { Input } from '@/components/ui/input' +import { Label } from '@/components/ui/label' +import { Switch } from '@/components/ui/switch' + +const meta = { + title: 'UI/Label', + component: Label, + args: { children: 'Frame rate' }, +} satisfies Meta + +export default meta + +type Story = StoryObj + +export const Default: Story = {} + +export const WithInput: Story = { + render: (args) => ( +
+
+ ), +} + +/** + * `peer-disabled:` dims the label when the control it labels is disabled — the + * label has to sit after the peer for the variant to apply. + */ +export const PeerDisabled: Story = { + render: () => ( +
+ + +
+ ), +} diff --git a/src/components/ui/popover.stories.tsx b/src/components/ui/popover.stories.tsx new file mode 100644 index 000000000..4c333b1dc --- /dev/null +++ b/src/components/ui/popover.stories.tsx @@ -0,0 +1,68 @@ +import type { Meta, StoryObj } from '@storybook/react-vite' +import { Button } from '@/components/ui/button' +import { Input } from '@/components/ui/input' +import { Label } from '@/components/ui/label' +import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover' + +const meta = { + title: 'UI/Popover', + component: Popover, +} satisfies Meta + +export default meta + +type Story = StoryObj + +export const Default: Story = { + args: { defaultOpen: true }, + render: (args) => ( +
+ + + + + +
+

Sequence settings

+

Applies to the open timeline.

+
+
+ + +
+
+
+
+ ), +} + +export const AlignStart: Story = { + args: { defaultOpen: true }, + render: (args) => ( +
+ + + + + + Content aligns to the trigger's leading edge. + + +
+ ), +} + +export const OnClick: Story = { + render: () => ( + + + + + + Dismisses on outside click or Escape. + + + ), +} diff --git a/src/components/ui/progress.stories.tsx b/src/components/ui/progress.stories.tsx new file mode 100644 index 000000000..0107506e6 --- /dev/null +++ b/src/components/ui/progress.stories.tsx @@ -0,0 +1,47 @@ +import type { Meta, StoryObj } from '@storybook/react-vite' +import { Progress } from '@/components/ui/progress' + +const meta = { + title: 'UI/Progress', + component: Progress, + args: { value: 45 }, + argTypes: { value: { control: { type: 'range', min: 0, max: 100, step: 1 } } }, +} satisfies Meta + +export default meta + +type Story = StoryObj + +export const Default: Story = { + render: (args) => , +} + +export const Steps: Story = { + render: () => ( +
+ {[0, 25, 60, 100].map((value) => ( +
+
+ Rendering + {value}% +
+ +
+ ))} +
+ ), +} + +/** Export dialogs pair the bar with a mono readout of frames done. */ +export const WithExportReadout: Story = { + args: { value: 72 }, + render: (args) => ( +
+
+ Exporting sequence + 1 728 / 2 400 +
+ +
+ ), +} diff --git a/src/components/ui/resizable.stories.tsx b/src/components/ui/resizable.stories.tsx new file mode 100644 index 000000000..c5de55518 --- /dev/null +++ b/src/components/ui/resizable.stories.tsx @@ -0,0 +1,85 @@ +import type { Meta, StoryObj } from '@storybook/react-vite' +import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from '@/components/ui/resizable' + +const meta = { + title: 'UI/Resizable', + component: ResizablePanelGroup, +} satisfies Meta + +export default meta + +type Story = StoryObj + +function Pane({ label }: { label: string }) { + return ( +
+ {label} +
+ ) +} + +export const Horizontal: Story = { + args: { direction: 'horizontal' }, + render: (args) => ( + + + + + + + + + + ), +} + +/** `withHandle` adds the grip — used where the divider is easy to miss. */ +export const WithGrip: Story = { + args: { direction: 'horizontal' }, + render: (args) => ( + + + + + + + + + + ), +} + +/** The editor's real shape: panels above, the timeline well below. */ +export const EditorLayout: Story = { + args: { direction: 'vertical' }, + render: (args) => ( + + + + + + + + + + + + + + +
+ Timeline +
+
+
+ ), +} diff --git a/src/components/ui/scroll-area.stories.tsx b/src/components/ui/scroll-area.stories.tsx new file mode 100644 index 000000000..560329087 --- /dev/null +++ b/src/components/ui/scroll-area.stories.tsx @@ -0,0 +1,51 @@ +import type { Meta, StoryObj } from '@storybook/react-vite' +import { ScrollArea } from '@/components/ui/scroll-area' + +const meta = { + title: 'UI/ScrollArea', + component: ScrollArea, +} satisfies Meta + +export default meta + +type Story = StoryObj + +const takes = Array.from({ length: 24 }, (_, index) => ({ + name: `A0${String(index + 1).padStart(2, '0')}_C${index + 1}.mov`, + duration: `00:0${index % 6}:${String((index * 7) % 60).padStart(2, '0')}:12`, +})) + +export const Vertical: Story = { + render: (args) => ( + +
+ {takes.map((take) => ( +
+ {take.name} + + {take.duration} + +
+ ))} +
+
+ ), +} + +/** Short content leaves the rail hidden — the scrollbar only fades in on overflow. */ +export const NoOverflow: Story = { + render: (args) => ( + +
+ {takes.slice(0, 3).map((take) => ( +
+ {take.name} +
+ ))} +
+
+ ), +} diff --git a/src/components/ui/select.stories.tsx b/src/components/ui/select.stories.tsx new file mode 100644 index 000000000..976e740a6 --- /dev/null +++ b/src/components/ui/select.stories.tsx @@ -0,0 +1,85 @@ +import type { Meta, StoryObj } from '@storybook/react-vite' +import { + Select, + SelectContent, + SelectGroup, + SelectItem, + SelectLabel, + SelectTrigger, + SelectValue, +} from '@/components/ui/select' + +const meta = { + title: 'UI/Select', + component: Select, +} satisfies Meta + +export default meta + +type Story = StoryObj + +export const Default: Story = { + render: (args) => ( + + ), +} + +export const WithValue: Story = { + args: { defaultValue: '23.976' }, + render: Default.render, +} + +export const Grouped: Story = { + args: { defaultValue: 'h264' }, + render: (args) => ( + + ), +} + +export const Disabled: Story = { + args: { disabled: true, defaultValue: '23.976' }, + render: Default.render, +} + +/** The trigger clamps to one line; long option labels truncate rather than wrap. */ +export const LongOptionLabels: Story = { + render: (args) => ( + + ), +} diff --git a/src/components/ui/separator.stories.tsx b/src/components/ui/separator.stories.tsx new file mode 100644 index 000000000..570b98710 --- /dev/null +++ b/src/components/ui/separator.stories.tsx @@ -0,0 +1,35 @@ +import type { Meta, StoryObj } from '@storybook/react-vite' +import { Separator } from '@/components/ui/separator' + +const meta = { + title: 'UI/Separator', + component: Separator, + argTypes: { orientation: { control: 'inline-radio', options: ['horizontal', 'vertical'] } }, +} satisfies Meta + +export default meta + +type Story = StoryObj + +export const Horizontal: Story = { + render: (args) => ( +
+

Sequence settings

+ +

1920 × 1080 · 23.976 fps

+
+ ), +} + +export const Vertical: Story = { + args: { orientation: 'vertical' }, + render: (args) => ( +
+ Edit + + Color + + Export +
+ ), +} diff --git a/src/components/ui/slider.stories.tsx b/src/components/ui/slider.stories.tsx new file mode 100644 index 000000000..e8d4e76be --- /dev/null +++ b/src/components/ui/slider.stories.tsx @@ -0,0 +1,45 @@ +import type { Meta, StoryObj } from '@storybook/react-vite' +import { Label } from '@/components/ui/label' +import { Slider } from '@/components/ui/slider' + +const meta = { + title: 'UI/Slider', + component: Slider, + args: { defaultValue: [60], min: 0, max: 100, step: 1 }, +} satisfies Meta + +export default meta + +type Story = StoryObj + +export const Default: Story = { + render: (args) => , +} + +export const WithValueReadout: Story = { + render: (args) => ( +
+
+ + 60% +
+ +
+ ), +} + +/** Two thumbs — the shape used for in/out range trims. */ +export const Range: Story = { + args: { defaultValue: [25, 75] }, + render: (args) => , +} + +export const Stepped: Story = { + args: { defaultValue: [50], step: 25 }, + render: (args) => , +} + +export const Disabled: Story = { + args: { disabled: true }, + render: (args) => , +} diff --git a/src/components/ui/sonner.stories.tsx b/src/components/ui/sonner.stories.tsx new file mode 100644 index 000000000..3fff9a550 --- /dev/null +++ b/src/components/ui/sonner.stories.tsx @@ -0,0 +1,72 @@ +import type { Meta, StoryObj } from '@storybook/react-vite' +import { toast } from 'sonner' +import { Button } from '@/components/ui/button' +import { Toaster } from '@/components/ui/sonner' + +const meta = { + title: 'UI/Toaster', + component: Toaster, +} satisfies Meta + +export default meta + +type Story = StoryObj + +/** + * One `Toaster` is mounted at the app root; features call `toast()` from sonner. + * It is pinned bottom-right with rich colours and a close button. + */ +export const Playground: Story = { + render: (args) => ( + <> + +
+ + + + + +
+ + ), +} + +/** Toasts stack bottom-up; the description line drops to muted ink. */ +export const Stacked: Story = { + render: (args) => ( + <> + + + + ), +} diff --git a/src/components/ui/switch.stories.tsx b/src/components/ui/switch.stories.tsx new file mode 100644 index 000000000..20d31e622 --- /dev/null +++ b/src/components/ui/switch.stories.tsx @@ -0,0 +1,49 @@ +import type { Meta, StoryObj } from '@storybook/react-vite' +import { Label } from '@/components/ui/label' +import { Switch } from '@/components/ui/switch' + +const meta = { + title: 'UI/Switch', + component: Switch, + argTypes: { checked: { control: 'boolean' }, disabled: { control: 'boolean' } }, +} satisfies Meta + +export default meta + +type Story = StoryObj + +export const Default: Story = {} + +export const Checked: Story = { args: { defaultChecked: true } } + +export const WithLabel: Story = { + render: (args) => ( +
+ + +
+ ), +} + +export const States: Story = { + render: () => ( +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ ), +} diff --git a/src/components/ui/tabs.stories.tsx b/src/components/ui/tabs.stories.tsx new file mode 100644 index 000000000..6c984cd50 --- /dev/null +++ b/src/components/ui/tabs.stories.tsx @@ -0,0 +1,68 @@ +import type { Meta, StoryObj } from '@storybook/react-vite' +import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs' + +const meta = { + title: 'UI/Tabs', + component: Tabs, + args: { defaultValue: 'edit' }, +} satisfies Meta + +export default meta + +type Story = StoryObj + +export const Default: Story = { + render: (args) => ( + + + Edit + Color + Audio + + + Trim, ripple and roll the selected clip. + + + Wheels, curves and scopes for the current grade. + + + Levels, EQ and fades for the selected audio clip. + + + ), +} + +export const WithDisabledTab: Story = { + render: (args) => ( + + + Edit + Color + + Effects + + + + Effects are unavailable until a clip is selected. + + + ), +} + +/** The list does not scroll — many tabs simply widen it, so panels cap the count. */ +export const ManyTabs: Story = { + render: (args) => ( + + + {['edit', 'color', 'audio', 'effects', 'text', 'export'].map((value) => ( + + {value} + + ))} + + + Six triggers is about the practical ceiling for a side panel. + + + ), +} diff --git a/src/components/ui/textarea.stories.tsx b/src/components/ui/textarea.stories.tsx new file mode 100644 index 000000000..543b50a6a --- /dev/null +++ b/src/components/ui/textarea.stories.tsx @@ -0,0 +1,42 @@ +import type { Meta, StoryObj } from '@storybook/react-vite' +import { Label } from '@/components/ui/label' +import { Textarea } from '@/components/ui/textarea' + +const meta = { + title: 'UI/Textarea', + component: Textarea, + args: { placeholder: 'Caption text…' }, + argTypes: { disabled: { control: 'boolean' } }, +} satisfies Meta + +export default meta + +type Story = StoryObj + +export const Default: Story = { + render: (args) =>