diff --git a/.changeset/eighty-dryers-yawn.md b/.changeset/eighty-dryers-yawn.md new file mode 100644 index 00000000..f70028a2 --- /dev/null +++ b/.changeset/eighty-dryers-yawn.md @@ -0,0 +1,5 @@ +--- +'@storybook/addon-mcp': patch +--- + +Add support for MCP App, rendering stories directly in the agent chat in MCP clients that support it diff --git a/.claude/settings.local.json b/.claude/settings.local.json index af549e60..5b21479e 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -5,7 +5,7 @@ "Bash(git checkout:*)", "Bash(git add:*)", "mcp__storybook-addon-mcp__get-storybook-story-instructions", - "mcp__storybook-addon-mcp__get-story-urls" + "mcp__storybook-addon-mcp__preview-stories" ], "deny": [], "ask": [] diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 0ce3250c..46978ad4 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -33,8 +33,8 @@ The addon supports configuring which toolsets are enabled: name: '@storybook/addon-mcp', options: { toolsets: { - dev: true, // get-story-urls, get-storybook-story-instructions - docs: true, // list-all-components, get-component-documentation + dev: true, // preview-stories, get-storybook-story-instructions + docs: true, // list-all-documentation, get-component-documentation }, experimentalFormat: 'markdown' // Output format: 'markdown' (default) or 'xml' } @@ -171,7 +171,7 @@ import pkgJson from '../package.json' with { type: 'json' }; **Naming:** -- Constants: `SCREAMING_SNAKE_CASE` (e.g., `GET_STORY_URLS_TOOL_NAME`) +- Constants: `SCREAMING_SNAKE_CASE` (e.g., `PREVIEW_STORIES_TOOL_NAME`) - Functions: `camelCase` - Types: `PascalCase` @@ -376,3 +376,7 @@ When working on data validation, refer to the following resources: - https://valibot.dev/ - https://github.com/paoloricciuti/tmcp/tree/main/packages/adapter-valibot + +When working with MCP Apps and/or the `preview-stories.ts` file, refer to the MCP App specification: + +- https://raw.githubusercontent.com/modelcontextprotocol/ext-apps/refs/heads/main/specification/draft/apps.mdx diff --git a/.github/instructions/addon-mcp.instructions.md b/.github/instructions/addon-mcp.instructions.md index 1c39ac90..cbc77527 100644 --- a/.github/instructions/addon-mcp.instructions.md +++ b/.github/instructions/addon-mcp.instructions.md @@ -25,7 +25,7 @@ This is a Storybook addon that runs an MCP (Model Context Protocol) server withi The addon supports two toolsets that can be enabled/disabled: 1. **`dev`** (default: true) - - `get-story-urls`: Retrieve story URLs from Storybook + - `preview-stories`: Retrieve story preview URLs from Storybook - `get-storybook-story-instructions`: Provide UI development guidelines 2. **`docs`** (default: true) @@ -80,7 +80,7 @@ src/ types.ts # Valibot schemas and AddonContext type ui-building-instructions.md # Template for agent UI development instructions tools/ - get-story-urls.ts # Tool to retrieve story URLs from Storybook + preview-stories.ts # Tool to retrieve story preview URLs from Storybook get-storybook-story-instructions.ts # Tool to provide UI development guidelines utils/ errors.ts # Error handling utilities @@ -173,7 +173,7 @@ pnpm test:ci # Run tests with coverage and CI reporters - **Overall Target**: >70% statement coverage - **src/utils**: 100% coverage (errors.ts, fetch-story-index.ts) -- **src/tools**: >90% coverage (get-story-urls.ts, get-storybook-story-instructions.ts) +- **src/tools**: >90% coverage (preview-stories.ts, get-storybook-story-instructions.ts) - **src**: Integration files (preset.ts, mcp-handler.ts, telemetry.ts) have partial coverage **Key Testing Patterns:** @@ -244,8 +244,8 @@ Tests run automatically on PRs and main branch pushes via `.github/workflows/che ### Naming Conventions -- Constants: SCREAMING_SNAKE_CASE (e.g., `GET_STORY_URLS_TOOL_NAME`) -- Functions: camelCase (e.g., `addGetStoryUrlsTool`, `createAddonMcpHandler`) +- Constants: SCREAMING_SNAKE_CASE (e.g., `PREVIEW_STORIES_TOOL_NAME`) +- Functions: camelCase (e.g., `addPreviewStoriesTool`, `createAddonMcpHandler`) - Types/Interfaces: PascalCase (e.g., `AddonContext`, `StoryInput`) ## Important Files @@ -263,7 +263,7 @@ Tests run automatically on PRs and main branch pushes via `.github/workflows/che - `src/mcp-handler.ts` - Main MCP server handler factory using tmcp - `src/telemetry.ts` - Telemetry tracking for usage analytics - `src/types.ts` - Valibot schemas and AddonContext interface -- `src/tools/get-story-urls.ts` - Tool to fetch story URLs from index.json +- `src/tools/preview-stories.ts` - Tool to preview stories from Storybook - `src/tools/get-storybook-story-instructions.ts` - Tool to provide framework-specific UI instructions - `src/utils/errors.ts` - Error handling utilities - `src/utils/fetch-story-index.ts` - Utility to fetch Storybook's story index @@ -483,7 +483,7 @@ pnpm test run --coverage # With coverage report - `src/utils/errors.test.ts` - Tests error handling utilities - `src/utils/fetch-story-index.test.ts` - Tests story index fetching -- `src/tools/get-story-urls.test.ts` - Tests story URL resolution tool +- `src/tools/preview-stories.test.ts` - Tests story preview tool - `src/tools/get-storybook-story-instructions.test.ts` - Tests UI instructions tool - `src/mcp-handler.test.ts` - Tests HTTP conversion utilities diff --git a/.github/instructions/eval.instructions.md b/.github/instructions/eval.instructions.md index da827380..dd1185ac 100644 --- a/.github/instructions/eval.instructions.md +++ b/.github/instructions/eval.instructions.md @@ -585,8 +585,7 @@ export default meta; type Story = StoryObj; export const Default: Story = { - play: async ({ canvasElement }) => { - const canvas = within(canvasElement); + play: async ({ canvas }) => { await userEvent.click(canvas.getByTestId('submit')); await expect(canvas.getByText('Success')).toBeInTheDocument(); } diff --git a/README.md b/README.md index 5b9186f1..5e439733 100644 --- a/README.md +++ b/README.md @@ -150,6 +150,22 @@ pnpm storybook This will build everything and start up Storybook with addon-mcp, and you can then connect your coding agent to it at `http://localhost:6006/mcp` and try it out. +### Working with the MCP App + +To work with and debug the MCP app that is rendered as part of the preview-stories tool, you can: + +1. Use the Insiders build of VSCode +2. Ensure the [chat.mcp.apps.enabled](vscode-insiders://settings/chat.mcp.apps.enabled) setting is enabled +3. Start up the repo's Storybook in watch mode by running `pnpm storybook` in the root +4. Restart VSCode and, open the [`.vscode/mcp.json`](./.vscode/mcp.json) file and ensure the Storybook MCP is marked as Running, otherwise click Start. +5. Open up a chat in VSCode and write a prompt like this: + +> Show me how all the button stories look, using the Storybook MCP + +6. After this first prompt, whenever you make changes, Storybook automatically restarts. Wait for it to be fully ready, then you can prompt _"Run the tool again"_. + +You can also use [the inspector from MCPJam](https://docs.mcpjam.com/getting-started) to have more low level control of the tool calls. + ### Formatting & Linting ```bash diff --git a/apps/internal-storybook/.claude/settings.local.json b/apps/internal-storybook/.claude/settings.local.json index e2d20378..f03bae59 100644 --- a/apps/internal-storybook/.claude/settings.local.json +++ b/apps/internal-storybook/.claude/settings.local.json @@ -1,8 +1,8 @@ { "permissions": { "allow": [ + "mcp__storybook-addon-mcp__preview-stories", "mcp__storybook-addon-mcp__get-storybook-story-instructions", - "mcp__storybook-addon-mcp__get-story-urls", "mcp__storybook-addon-mcp__list-all-documentation", "mcp__storybook-addon-mcp__get-documentation" ] diff --git a/apps/internal-storybook/.storybook/main.ts b/apps/internal-storybook/.storybook/main.ts index bee3c4d9..de1536f0 100644 --- a/apps/internal-storybook/.storybook/main.ts +++ b/apps/internal-storybook/.storybook/main.ts @@ -12,6 +12,7 @@ const config = defineMain({ ], addons: [ '@storybook/addon-docs', + '@storybook/addon-themes', { name: '@storybook/addon-mcp', options: { @@ -23,7 +24,7 @@ const config = defineMain({ }, ], framework: '@storybook/react-vite', - logLevel: 'debug', + // logLevel: 'debug', core: { disableTelemetry: true, }, diff --git a/apps/internal-storybook/.storybook/preview.ts b/apps/internal-storybook/.storybook/preview.ts index 163d9ff7..571dafbb 100644 --- a/apps/internal-storybook/.storybook/preview.ts +++ b/apps/internal-storybook/.storybook/preview.ts @@ -1,4 +1,7 @@ import type { Preview } from '@storybook/react-vite'; +import { withThemeByDataAttribute } from '@storybook/addon-themes'; + +import '../stories/theme.css'; const preview: Preview = { parameters: { @@ -9,8 +12,18 @@ const preview: Preview = { }, }, }, + decorators: [ + withThemeByDataAttribute({ + themes: { + light: 'light', + dark: 'dark', + }, + defaultTheme: 'light', + attributeName: 'data-theme', + }), + ], initialGlobals: { - background: { value: 'light' }, + theme: 'light', }, }; diff --git a/apps/internal-storybook/package.json b/apps/internal-storybook/package.json index 935f836e..25a393aa 100644 --- a/apps/internal-storybook/package.json +++ b/apps/internal-storybook/package.json @@ -12,6 +12,7 @@ "devDependencies": { "@storybook/addon-docs": "catalog:", "@storybook/addon-mcp": "workspace:*", + "@storybook/addon-themes": "^10.2.0", "@storybook/react-vite": "catalog:", "@types/react": "^18.2.65", "@types/react-dom": "^18.2.21", diff --git a/apps/internal-storybook/stories/components/button.css b/apps/internal-storybook/stories/components/button.css index a3f1a306..f9c0ea39 100644 --- a/apps/internal-storybook/stories/components/button.css +++ b/apps/internal-storybook/stories/components/button.css @@ -6,15 +6,22 @@ cursor: pointer; display: inline-block; line-height: 1; + transition: + background-color 0.2s ease, + color 0.2s ease; } .storybook-button--primary { color: white; - background-color: #1ea7fd; + background-color: var(--color-primary, #1ea7fd); +} +.storybook-button--primary:hover { + background-color: var(--color-primary-hover, #1890d4); } .storybook-button--secondary { - color: #333; - background-color: transparent; - box-shadow: rgba(0, 0, 0, 0.15) 0px 0px 0px 1px inset; + color: var(--color-secondary-text, #333); + background-color: var(--color-secondary-bg, transparent); + box-shadow: var(--color-secondary-border, rgba(0, 0, 0, 0.15)) 0px 0px 0px 1px + inset; } .storybook-button--small { font-size: 12px; diff --git a/apps/internal-storybook/stories/components/header.css b/apps/internal-storybook/stories/components/header.css index f1e16841..8764de7b 100644 --- a/apps/internal-storybook/stories/components/header.css +++ b/apps/internal-storybook/stories/components/header.css @@ -1,10 +1,14 @@ .wrapper { font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif; - border-bottom: 1px solid rgba(0, 0, 0, 0.1); + border-bottom: 1px solid var(--color-border, rgba(0, 0, 0, 0.1)); padding: 15px 20px; display: flex; align-items: center; justify-content: space-between; + background-color: var(--color-bg, #ffffff); + transition: + background-color 0.2s ease, + border-color 0.2s ease; } svg { @@ -12,6 +16,10 @@ svg { vertical-align: top; } +svg g path:first-child { + fill: var(--color-logo-bg, #ffffff); +} + h1 { font-weight: 700; font-size: 20px; @@ -19,6 +27,7 @@ h1 { margin: 6px 0 6px 10px; display: inline-block; vertical-align: top; + color: var(--color-text, #333); } button + button { @@ -26,7 +35,7 @@ button + button { } .welcome { - color: #333; + color: var(--color-text, #333); font-size: 14px; margin-right: 10px; } diff --git a/apps/internal-storybook/stories/components/page.css b/apps/internal-storybook/stories/components/page.css index 60ee8ce5..cad36e50 100644 --- a/apps/internal-storybook/stories/components/page.css +++ b/apps/internal-storybook/stories/components/page.css @@ -5,7 +5,11 @@ section { padding: 48px 20px; margin: 0 auto; max-width: 600px; - color: #333; + color: var(--color-text, #333); + background-color: var(--color-bg, #ffffff); + transition: + background-color 0.2s ease, + color 0.2s ease; } section h2 { @@ -15,20 +19,23 @@ section h2 { margin: 0 0 4px; display: inline-block; vertical-align: top; + color: var(--color-text, #333); } section p { margin: 1em 0; + color: var(--color-text-secondary, #666); } section a { text-decoration: none; - color: #1ea7fd; + color: var(--color-link, #1ea7fd); } section ul { padding-left: 30px; margin: 1em 0; + color: var(--color-text-secondary, #666); } section li { @@ -41,8 +48,8 @@ section .tip { font-size: 11px; line-height: 12px; font-weight: 700; - background: #e7fdd8; - color: #66bf3c; + background: var(--color-tip-bg, #e7fdd8); + color: var(--color-tip-text, #66bf3c); padding: 4px 12px; margin-right: 10px; vertical-align: top; @@ -53,6 +60,7 @@ section .tip-wrapper { line-height: 20px; margin-top: 40px; margin-bottom: 40px; + color: var(--color-text-secondary, #666); } section .tip-wrapper svg { @@ -65,5 +73,5 @@ section .tip-wrapper svg { } section .tip-wrapper svg path { - fill: #1ea7fd; + fill: var(--color-link, #1ea7fd); } diff --git a/apps/internal-storybook/stories/other/card/card.css b/apps/internal-storybook/stories/other/card/card.css index c1b7044e..a67f6efd 100644 --- a/apps/internal-storybook/stories/other/card/card.css +++ b/apps/internal-storybook/stories/other/card/card.css @@ -1,18 +1,22 @@ .storybook-card { font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif; - border: 1px solid #e1e5e9; + border: 1px solid var(--color-border-strong, #e1e5e9); border-radius: 8px; padding: 16px; max-width: 300px; - background-color: white; - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + background-color: var(--color-bg, white); + box-shadow: 0 2px 4px var(--color-card-shadow, rgba(0, 0, 0, 0.1)); + transition: + background-color 0.2s ease, + border-color 0.2s ease, + box-shadow 0.2s ease; } .storybook-card__title { margin: 0 0 12px 0; font-size: 18px; font-weight: 700; - color: #333; + color: var(--color-text, #333); } .storybook-card__image { @@ -27,7 +31,7 @@ margin: 0 0 16px 0; font-size: 14px; line-height: 1.5; - color: #666; + color: var(--color-text-secondary, #666); } .storybook-card__button { @@ -41,10 +45,10 @@ display: inline-block; line-height: 1; color: white; - background-color: #1ea7fd; + background-color: var(--color-primary, #1ea7fd); transition: background-color 0.2s ease; } .storybook-card__button:hover { - background-color: #1890d4; + background-color: var(--color-primary-hover, #1890d4); } diff --git a/apps/internal-storybook/stories/theme.css b/apps/internal-storybook/stories/theme.css new file mode 100644 index 00000000..8b63c967 --- /dev/null +++ b/apps/internal-storybook/stories/theme.css @@ -0,0 +1,51 @@ +/* Light theme (default) */ +:root, +[data-theme='light'] { + --color-bg: #ffffff; + --color-bg-secondary: #f8f9fa; + --color-text: #333333; + --color-text-secondary: #666666; + --color-text-muted: #999999; + --color-border: rgba(0, 0, 0, 0.1); + --color-border-strong: #e1e5e9; + --color-primary: #1ea7fd; + --color-primary-hover: #1890d4; + --color-secondary-bg: transparent; + --color-secondary-text: #333333; + --color-secondary-border: rgba(0, 0, 0, 0.15); + --color-tip-bg: #e7fdd8; + --color-tip-text: #66bf3c; + --color-link: #1ea7fd; + --color-card-shadow: rgba(0, 0, 0, 0.1); + --color-logo-bg: #ffffff; +} + +/* Dark theme */ +[data-theme='dark'] { + --color-bg: #1a1a2e; + --color-bg-secondary: #16213e; + --color-text: #eaeaea; + --color-text-secondary: #b8b8b8; + --color-text-muted: #888888; + --color-border: rgba(255, 255, 255, 0.1); + --color-border-strong: #2a2a4a; + --color-primary: #4dabf7; + --color-primary-hover: #74c0fc; + --color-secondary-bg: transparent; + --color-secondary-text: #eaeaea; + --color-secondary-border: rgba(255, 255, 255, 0.2); + --color-tip-bg: #1a3a1a; + --color-tip-text: #8bc34a; + --color-link: #4dabf7; + --color-card-shadow: rgba(0, 0, 0, 0.3); + --color-logo-bg: #2a2a4a; +} + +/* Base body styles */ +body { + background-color: var(--color-bg); + color: var(--color-text); + transition: + background-color 0.2s ease, + color 0.2s ease; +} diff --git a/apps/internal-storybook/tests/mcp-endpoint.e2e.test.ts b/apps/internal-storybook/tests/mcp-endpoint.e2e.test.ts index 63d0fd66..4394af2a 100644 --- a/apps/internal-storybook/tests/mcp-endpoint.e2e.test.ts +++ b/apps/internal-storybook/tests/mcp-endpoint.e2e.test.ts @@ -166,7 +166,12 @@ describe('MCP Endpoint E2E Tests', () => { expect(response.result.tools).toMatchInlineSnapshot(` [ { - "description": "Get the URL for one or more stories.", + "_meta": { + "ui": { + "resourceUri": "ui://preview-stories/preview.html", + }, + }, + "description": "Use this tool to preview one or more stories, rendering them as an MCP App using the UI Resource or returning the raw URL for users to visit.", "inputSchema": { "$schema": "http://json-schema.org/draft-07/schema#", "properties": { @@ -177,11 +182,26 @@ describe('MCP Endpoint E2E Tests', () => { "type": "string", }, "explicitStoryName": { + "description": "If the story has an explicit name set via the "name" propoerty, that is different from the export name, provide it here. + Otherwise don't set this.", "type": "string", }, "exportName": { "type": "string", }, + "globals": { + "additionalProperties": {}, + "description": "Optional Storybook globals to set for the story preview. Globals are used for things like theme, locale, viewport, and other cross-cutting concerns. + Common globals include 'theme' (e.g., 'dark', 'light'), 'locale' (e.g., 'en', 'fr'), and 'backgrounds' (e.g., { value: '#000' }).", + "type": "object", + }, + "props": { + "additionalProperties": {}, + "description": "Optional custom props to pass to the story for rendering. Use this when you don't want to render the default story, + but you want to customize some args or other props. + You can look up the component's documentation using the get-storybook-story-instructions tool to see what props are available.", + "type": "object", + }, }, "required": [ "exportName", @@ -197,8 +217,88 @@ describe('MCP Endpoint E2E Tests', () => { ], "type": "object", }, - "name": "get-story-urls", - "title": "Get stories' URLs", + "name": "preview-stories", + "outputSchema": { + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "stories": { + "items": { + "anyOf": [ + { + "properties": { + "name": { + "type": "string", + }, + "previewUrl": { + "type": "string", + }, + "title": { + "type": "string", + }, + }, + "required": [ + "title", + "name", + "previewUrl", + ], + "type": "object", + }, + { + "properties": { + "error": { + "type": "string", + }, + "input": { + "properties": { + "absoluteStoryPath": { + "type": "string", + }, + "explicitStoryName": { + "description": "If the story has an explicit name set via the "name" propoerty, that is different from the export name, provide it here. + Otherwise don't set this.", + "type": "string", + }, + "exportName": { + "type": "string", + }, + "globals": { + "additionalProperties": {}, + "description": "Optional Storybook globals to set for the story preview. Globals are used for things like theme, locale, viewport, and other cross-cutting concerns. + Common globals include 'theme' (e.g., 'dark', 'light'), 'locale' (e.g., 'en', 'fr'), and 'backgrounds' (e.g., { value: '#000' }).", + "type": "object", + }, + "props": { + "additionalProperties": {}, + "description": "Optional custom props to pass to the story for rendering. Use this when you don't want to render the default story, + but you want to customize some args or other props. + You can look up the component's documentation using the get-storybook-story-instructions tool to see what props are available.", + "type": "object", + }, + }, + "required": [ + "exportName", + "absoluteStoryPath", + ], + "type": "object", + }, + }, + "required": [ + "input", + "error", + ], + "type": "object", + }, + ], + }, + "type": "array", + }, + }, + "required": [ + "stories", + ], + "type": "object", + }, + "title": "Preview stories", }, { "description": "Get comprehensive instructions for writing and updating Storybook stories (.stories.tsx, .stories.ts, .stories.jsx, .stories.js, .stories.svelte, .stories.vue files). @@ -258,7 +358,7 @@ describe('MCP Endpoint E2E Tests', () => { }); }); - describe('Tool: get-story-urls', () => { + describe('Tool: preview-stories', () => { it('should return story URLs for valid stories', async () => { const cwd = process.cwd(); const storyPath = cwd.endsWith('/apps/internal-storybook') @@ -266,7 +366,7 @@ describe('MCP Endpoint E2E Tests', () => { : `${cwd}/apps/internal-storybook/stories/components/Button.stories.ts`; const response = await mcpRequest('tools/call', { - name: 'get-story-urls', + name: 'preview-stories', arguments: { stories: [ { @@ -285,13 +385,22 @@ describe('MCP Endpoint E2E Tests', () => { "type": "text", }, ], + "structuredContent": { + "stories": [ + { + "name": "Primary", + "previewUrl": "http://localhost:6006/?path=/story/example-button--primary", + "title": "Example/Button", + }, + ], + }, } `); }); it('should return error message for non-existent story', async () => { const response = await mcpRequest('tools/call', { - name: 'get-story-urls', + name: 'preview-stories', arguments: { stories: [ { @@ -494,7 +603,7 @@ describe('MCP Endpoint E2E Tests', () => { expect(toolNames).toMatchInlineSnapshot(` [ - "get-story-urls", + "preview-stories", "get-storybook-story-instructions", ] `); diff --git a/package.json b/package.json index f567070c..f462535a 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "lint:ci": "oxlint --format github --type-aware", "publint": "turbo run publint", "release": "turbo run build && pnpm changeset publish", - "storybook": "turbo watch storybook", + "storybook": "turbo watch storybook --filter=@storybook/mcp-internal-storybook", "test": "vitest", "test:ci": "vitest run --coverage --reporter=default --reporter=github-actions --reporter=junit --outputFile=test-report.junit.xml", "test:run": "vitest run", diff --git a/packages/addon-mcp/README.md b/packages/addon-mcp/README.md index 4830028e..0d386144 100644 --- a/packages/addon-mcp/README.md +++ b/packages/addon-mcp/README.md @@ -153,7 +153,7 @@ Provides agents with standardized instructions for UI component development with The instructions ensure agents follow your project's conventions when creating or modifying UI components and their corresponding stories. -#### 2. Get Story URLs (`get_story_urls`) +#### 2. Preview Stories (`preview-stories`) Allows agents to retrieve direct URLs to specific stories in your Storybook. The agent can request URLs for multiple stories by providing: diff --git a/packages/addon-mcp/package.json b/packages/addon-mcp/package.json index 89e49699..87726436 100644 --- a/packages/addon-mcp/package.json +++ b/packages/addon-mcp/package.json @@ -16,6 +16,7 @@ "type": "module", "exports": { "./preset": "./dist/preset.js", + "./internal/preview-stories-app-script": "./dist/preview-stories-app-script.js", "./package.json": "./package.json" }, "files": [ @@ -36,6 +37,7 @@ "@storybook/mcp": "workspace:*", "@tmcp/adapter-valibot": "catalog:", "@tmcp/transport-http": "catalog:", + "picoquery": "^2.5.0", "tmcp": "catalog:", "valibot": "catalog:" }, diff --git a/packages/addon-mcp/src/constants.ts b/packages/addon-mcp/src/constants.ts new file mode 100644 index 00000000..05fc627b --- /dev/null +++ b/packages/addon-mcp/src/constants.ts @@ -0,0 +1,2 @@ +export const MCP_APP_PARAM = 'mcp-app'; +export const MCP_APP_SIZE_CHANGED_EVENT = 'storybook-mcp:size-changed'; diff --git a/packages/addon-mcp/src/mcp-handler.ts b/packages/addon-mcp/src/mcp-handler.ts index 14a4e8d5..e2ec2606 100644 --- a/packages/addon-mcp/src/mcp-handler.ts +++ b/packages/addon-mcp/src/mcp-handler.ts @@ -2,7 +2,7 @@ import { McpServer } from 'tmcp'; import { ValibotJsonSchemaAdapter } from '@tmcp/adapter-valibot'; import { HttpTransport } from '@tmcp/transport-http'; import pkgJson from '../package.json' with { type: 'json' }; -import { addGetStoryUrlsTool } from './tools/get-story-urls.ts'; +import { addPreviewStoriesTool } from './tools/preview-stories.ts'; import { addGetUIBuildingInstructionsTool } from './tools/get-storybook-story-instructions.ts'; import { addListAllDocumentationTool, @@ -37,6 +37,7 @@ const initializeMCPServer = async (options: Options) => { adapter: new ValibotJsonSchemaAdapter(), capabilities: { tools: { listChanged: true }, + resources: { listChanged: true }, }, }, ).withContext(); @@ -48,7 +49,7 @@ const initializeMCPServer = async (options: Options) => { } // Register dev addon tools - await addGetStoryUrlsTool(server); + await addPreviewStoriesTool(server); await addGetUIBuildingInstructionsTool(server); // Only register the additional tools if the component manifest feature is enabled diff --git a/packages/addon-mcp/src/preset.ts b/packages/addon-mcp/src/preset.ts index 19c80ddc..63de9d82 100644 --- a/packages/addon-mcp/src/preset.ts +++ b/packages/addon-mcp/src/preset.ts @@ -1,11 +1,18 @@ import { mcpServerHandler } from './mcp-handler.ts'; -import type { PresetProperty } from 'storybook/internal/types'; +import type { PresetPropertyFn } from 'storybook/internal/types'; import { AddonOptions } from './types.ts'; import * as v from 'valibot'; import { getManifestStatus } from './tools/is-manifest-available.ts'; import htmlTemplate from './template.html'; +import path from 'node:path'; -export const experimental_devServer: PresetProperty< +export const previewAnnotations: PresetPropertyFn< + 'previewAnnotations' +> = async (existingAnnotations = []) => { + return [...existingAnnotations, path.join(import.meta.dirname, 'preview.js')]; +}; + +export const experimental_devServer: PresetPropertyFn< 'experimental_devServer' > = async (app, options) => { // There is no error handling here. This can make the whole storybook app crash with: diff --git a/packages/addon-mcp/src/preview.ts b/packages/addon-mcp/src/preview.ts new file mode 100644 index 00000000..63921d91 --- /dev/null +++ b/packages/addon-mcp/src/preview.ts @@ -0,0 +1,68 @@ +/** + * Storybook MCP App Script + * + * This script runs inside Storybook's iframe and communicates dimensions + * to the parent preview.html frame via postMessage (cross-origin safe). + * + * Only activates when the iframe is loaded with `mcp-app=true` query parameter, + * which is set by the MCP Apps preview.html wrapper. + */ + +import { MCP_APP_PARAM, MCP_APP_SIZE_CHANGED_EVENT } from './constants'; +// Only run if we're in the special MCP App iframe context +const isMcpApp = new URLSearchParams(window.location.search).has(MCP_APP_PARAM); + +if (isMcpApp) { + const SIZE_CHANGE_THRESHOLD = 2; // Only report changes > 2px to avoid oscillation + + let debounceTimer: ReturnType | null = null; + let lastSentHeight = 0; + const DEBOUNCE_MS = 100; + + function sendSizeToParent() { + const height = document.body.scrollHeight; + + // Only send if the change exceeds the threshold + if (Math.abs(height - lastSentHeight) <= SIZE_CHANGE_THRESHOLD) { + return; + } + + lastSentHeight = height; + window.parent.postMessage( + { + type: MCP_APP_SIZE_CHANGED_EVENT, + height, + }, + '*', + ); + } + + function debouncedSendSize() { + if (debounceTimer) { + clearTimeout(debounceTimer); + } + debounceTimer = setTimeout(sendSizeToParent, DEBOUNCE_MS); + } + + // Send initial size after DOM is ready + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', sendSizeToParent); + } else { + sendSizeToParent(); + } + + // Also send after full load (images, fonts, etc.) + window.addEventListener('load', sendSizeToParent); + + // Observe body for size changes using ResizeObserver + const resizeObserver = new ResizeObserver(debouncedSendSize); + resizeObserver.observe(document.body); + + // Also observe for DOM mutations that might affect size + const mutationObserver = new MutationObserver(debouncedSendSize); + mutationObserver.observe(document.body, { + childList: true, + subtree: true, + attributes: true, + }); +} diff --git a/packages/addon-mcp/src/storybook-story-instructions.md b/packages/addon-mcp/src/storybook-story-instructions.md index 0c087aa7..72300be6 100644 --- a/packages/addon-mcp/src/storybook-story-instructions.md +++ b/packages/addon-mcp/src/storybook-story-instructions.md @@ -147,4 +147,4 @@ play: async ({ canvas }) => { - ALWAYS provide story links after any changes to stories files, including changes to existing stories. - After changing any UI components, ALWAYS search for related stories that might cover the changes you've made. If you find any, provide the story links to the user. THIS IS VERY IMPORTANT, as it allows the user to visually inspect the changes you've made. Even later in a session when changing UI components or stories that have already been linked to previously, YOU MUST PROVIDE THE LINKS AGAIN. -- Use the {{GET_STORY_URLS_TOOL_NAME}} tool to get the correct URLs for links to stories. +- Use the {{PREVIEW_STORIES_TOOL_NAME}} tool to get the correct URLs for links to stories. diff --git a/packages/addon-mcp/src/template.html b/packages/addon-mcp/src/template.html index 8505a1d5..c1ae9f08 100644 --- a/packages/addon-mcp/src/template.html +++ b/packages/addon-mcp/src/template.html @@ -204,7 +204,7 @@

Available Toolsets

{{DEV_STATUS}}
    -
  • get-story-urls
  • +
  • preview-stories
  • get-storybook-story-instructions
diff --git a/packages/addon-mcp/src/tools/get-story-urls.ts b/packages/addon-mcp/src/tools/get-story-urls.ts deleted file mode 100644 index 8458c288..00000000 --- a/packages/addon-mcp/src/tools/get-story-urls.ts +++ /dev/null @@ -1,103 +0,0 @@ -import type { McpServer } from 'tmcp'; -import path from 'node:path'; -import { storyNameFromExport } from 'storybook/internal/csf'; -import { logger } from 'storybook/internal/node-logger'; -import * as v from 'valibot'; -import { collectTelemetry } from '../telemetry.ts'; -import { fetchStoryIndex } from '../utils/fetch-story-index.ts'; -import { errorToMCPContent } from '../utils/errors.ts'; -import type { AddonContext } from '../types.ts'; -import { StoryInputArray } from '../types.ts'; - -export const GET_STORY_URLS_TOOL_NAME = 'get-story-urls'; - -const GetStoryUrlsInput = v.object({ - stories: StoryInputArray, -}); - -type GetStoryUrlsInput = v.InferOutput; - -export async function addGetStoryUrlsTool( - server: McpServer, -) { - server.tool( - { - name: GET_STORY_URLS_TOOL_NAME, - title: "Get stories' URLs", - description: `Get the URL for one or more stories.`, - schema: GetStoryUrlsInput, - enabled: () => server.ctx.custom?.toolsets?.dev ?? true, - }, - async (input: GetStoryUrlsInput) => { - try { - const { origin, disableTelemetry } = server.ctx.custom ?? {}; - - if (!origin) { - throw new Error('Origin is required in addon context'); - } - - const index = await fetchStoryIndex(origin); - const entriesList = Object.values(index.entries); - - const result: string[] = []; - let foundStoryCount = 0; - - for (const { - exportName, - explicitStoryName, - absoluteStoryPath, - } of input.stories) { - const relativePath = `./${path.relative(process.cwd(), absoluteStoryPath)}`; - - logger.debug('Searching for:'); - logger.debug({ - exportName, - explicitStoryName, - absoluteStoryPath, - relativePath, - }); - - const foundStoryId = entriesList.find( - (entry) => - entry.importPath === relativePath && - [explicitStoryName, storyNameFromExport(exportName)].includes( - entry.name, - ), - )?.id; - - if (foundStoryId) { - logger.debug(`Found story ID: ${foundStoryId}`); - result.push(`${origin}/?path=/story/${foundStoryId}`); - foundStoryCount++; - } else { - logger.debug('No story found'); - let errorMessage = `No story found for export name "${exportName}" with absolute file path "${absoluteStoryPath}"`; - if (!explicitStoryName) { - errorMessage += ` (did you forget to pass the explicit story name?)`; - } - result.push(errorMessage); - } - } - - if (!disableTelemetry) { - await collectTelemetry({ - event: 'tool:getStoryUrls', - server, - toolset: 'dev', - inputStoryCount: input.stories.length, - outputStoryCount: foundStoryCount, - }); - } - - return { - content: result.map((text) => ({ - type: 'text', - text, - })), - }; - } catch (error) { - return errorToMCPContent(error); - } - }, - ); -} diff --git a/packages/addon-mcp/src/tools/get-storybook-story-instructions.test.ts b/packages/addon-mcp/src/tools/get-storybook-story-instructions.test.ts index aa6e1aa5..58c764ca 100644 --- a/packages/addon-mcp/src/tools/get-storybook-story-instructions.test.ts +++ b/packages/addon-mcp/src/tools/get-storybook-story-instructions.test.ts @@ -6,7 +6,7 @@ import { GET_UI_BUILDING_INSTRUCTIONS_TOOL_NAME, } from './get-storybook-story-instructions.ts'; import type { AddonContext } from '../types.ts'; -import { GET_STORY_URLS_TOOL_NAME } from './get-story-urls.ts'; +import { PREVIEW_STORIES_TOOL_NAME } from './preview-stories.ts'; describe('getUIBuildingInstructionsTool', () => { let server: McpServer; @@ -80,12 +80,12 @@ describe('getUIBuildingInstructionsTool', () => { // Check that placeholders were replaced expect(instructions).toContain('@storybook/react-vite'); expect(instructions).toContain('@storybook/react'); - expect(instructions).toContain(GET_STORY_URLS_TOOL_NAME); + expect(instructions).toContain(PREVIEW_STORIES_TOOL_NAME); // Check that no placeholders remain expect(instructions).not.toContain('{{FRAMEWORK}}'); expect(instructions).not.toContain('{{RENDERER}}'); - expect(instructions).not.toContain('{{GET_STORY_URLS_TOOL_NAME}}'); + expect(instructions).not.toContain('{{PREVIEW_STORIES_TOOL_NAME}}'); }); it('should handle Vue framework', async () => { diff --git a/packages/addon-mcp/src/tools/get-storybook-story-instructions.ts b/packages/addon-mcp/src/tools/get-storybook-story-instructions.ts index d3c89d14..4edd1058 100644 --- a/packages/addon-mcp/src/tools/get-storybook-story-instructions.ts +++ b/packages/addon-mcp/src/tools/get-storybook-story-instructions.ts @@ -1,5 +1,5 @@ import type { McpServer } from 'tmcp'; -import { GET_STORY_URLS_TOOL_NAME } from './get-story-urls.ts'; +import { PREVIEW_STORIES_TOOL_NAME } from './preview-stories.ts'; import { collectTelemetry } from '../telemetry.ts'; import storyInstructionsTemplate from '../storybook-story-instructions.md'; import { errorToMCPContent } from '../utils/errors.ts'; @@ -61,7 +61,7 @@ Even if you're familiar with Storybook, call this tool to ensure you're followin const uiInstructions = storyInstructionsTemplate .replace('{{FRAMEWORK}}', framework) .replace('{{RENDERER}}', renderer ?? framework) - .replace('{{GET_STORY_URLS_TOOL_NAME}}', GET_STORY_URLS_TOOL_NAME); + .replace('{{PREVIEW_STORIES_TOOL_NAME}}', PREVIEW_STORIES_TOOL_NAME); return { content: [{ type: 'text' as const, text: uiInstructions }], diff --git a/packages/addon-mcp/src/tools/get-story-urls.test.ts b/packages/addon-mcp/src/tools/preview-stories.test.ts similarity index 66% rename from packages/addon-mcp/src/tools/get-story-urls.test.ts rename to packages/addon-mcp/src/tools/preview-stories.test.ts index 83583f7d..31173b0f 100644 --- a/packages/addon-mcp/src/tools/get-story-urls.test.ts +++ b/packages/addon-mcp/src/tools/preview-stories.test.ts @@ -2,9 +2,9 @@ import { describe, it, expect, vi, beforeEach } from 'vitest'; import { McpServer } from 'tmcp'; import { ValibotJsonSchemaAdapter } from '@tmcp/adapter-valibot'; import { - addGetStoryUrlsTool, - GET_STORY_URLS_TOOL_NAME, -} from './get-story-urls.ts'; + addPreviewStoriesTool, + PREVIEW_STORIES_TOOL_NAME, +} from './preview-stories.ts'; import type { AddonContext } from '../types.ts'; import smallStoryIndexFixture from '../../fixtures/small-story-index.fixture.json' with { type: 'json' }; import * as fetchStoryIndex from '../utils/fetch-story-index.ts'; @@ -13,7 +13,7 @@ vi.mock('storybook/internal/csf', () => ({ storyNameFromExport: (exportName: string) => exportName, })); -describe('getStoryUrlsTool', () => { +describe('previewStoriesTool', () => { let server: McpServer; let fetchStoryIndexSpy: any; const testContext: AddonContext = { @@ -28,7 +28,7 @@ describe('getStoryUrlsTool', () => { { name: 'test-server', version: '1.0.0', - description: 'Test server for get-story-urls tool', + description: 'Test server for preview-stories tool', }, { adapter, @@ -55,7 +55,7 @@ describe('getStoryUrlsTool', () => { }, ); - await addGetStoryUrlsTool(server); + await addPreviewStoriesTool(server); // Mock fetchStoryIndex to return the fixture fetchStoryIndexSpy = vi.spyOn(fetchStoryIndex, 'fetchStoryIndex'); @@ -68,7 +68,7 @@ describe('getStoryUrlsTool', () => { id: 1, method: 'tools/call', params: { - name: GET_STORY_URLS_TOOL_NAME, + name: PREVIEW_STORIES_TOOL_NAME, arguments: { stories: [ { @@ -92,6 +92,15 @@ describe('getStoryUrlsTool', () => { text: 'http://localhost:6006/?path=/story/button--primary', }, ], + structuredContent: { + stories: [ + { + title: 'Button', + name: 'Primary', + previewUrl: 'http://localhost:6006/?path=/story/button--primary', + }, + ], + }, }); expect(fetchStoryIndexSpy).toHaveBeenCalledWith('http://localhost:6006'); }); @@ -102,7 +111,7 @@ describe('getStoryUrlsTool', () => { id: 1, method: 'tools/call', params: { - name: GET_STORY_URLS_TOOL_NAME, + name: PREVIEW_STORIES_TOOL_NAME, arguments: { stories: [ { @@ -142,6 +151,25 @@ describe('getStoryUrlsTool', () => { text: 'http://localhost:6006/?path=/story/input--default', }, ], + structuredContent: { + stories: [ + { + title: 'Button', + name: 'Primary', + previewUrl: 'http://localhost:6006/?path=/story/button--primary', + }, + { + title: 'Button', + name: 'Secondary', + previewUrl: 'http://localhost:6006/?path=/story/button--secondary', + }, + { + title: 'Input', + name: 'Default', + previewUrl: 'http://localhost:6006/?path=/story/input--default', + }, + ], + }, }); }); @@ -151,7 +179,7 @@ describe('getStoryUrlsTool', () => { id: 1, method: 'tools/call', params: { - name: GET_STORY_URLS_TOOL_NAME, + name: PREVIEW_STORIES_TOOL_NAME, arguments: { stories: [ { @@ -182,7 +210,7 @@ describe('getStoryUrlsTool', () => { id: 1, method: 'tools/call', params: { - name: GET_STORY_URLS_TOOL_NAME, + name: PREVIEW_STORIES_TOOL_NAME, arguments: { stories: [ { @@ -207,6 +235,15 @@ describe('getStoryUrlsTool', () => { text: 'http://localhost:6006/?path=/story/button--primary', }, ], + structuredContent: { + stories: [ + { + title: 'Button', + name: 'Primary', + previewUrl: 'http://localhost:6006/?path=/story/button--primary', + }, + ], + }, }); }); @@ -216,7 +253,7 @@ describe('getStoryUrlsTool', () => { id: 1, method: 'tools/call', params: { - name: GET_STORY_URLS_TOOL_NAME, + name: PREVIEW_STORIES_TOOL_NAME, arguments: { stories: [ { @@ -254,7 +291,7 @@ describe('getStoryUrlsTool', () => { id: 1, method: 'tools/call', params: { - name: GET_STORY_URLS_TOOL_NAME, + name: PREVIEW_STORIES_TOOL_NAME, arguments: { stories: [ { @@ -274,7 +311,7 @@ describe('getStoryUrlsTool', () => { expect(telemetry).toHaveBeenCalledWith( 'addon-mcp', expect.objectContaining({ - event: 'tool:getStoryUrls', + event: 'tool:previewStories', mcpSessionId: 'test-session', toolset: 'dev', inputStoryCount: 1, @@ -289,7 +326,7 @@ describe('getStoryUrlsTool', () => { id: 1, method: 'tools/call', params: { - name: GET_STORY_URLS_TOOL_NAME, + name: PREVIEW_STORIES_TOOL_NAME, arguments: { stories: [ { @@ -328,7 +365,7 @@ describe('getStoryUrlsTool', () => { id: 1, method: 'tools/call', params: { - name: GET_STORY_URLS_TOOL_NAME, + name: PREVIEW_STORIES_TOOL_NAME, arguments: { stories: [ { @@ -355,4 +392,111 @@ describe('getStoryUrlsTool', () => { isError: true, }); }); + + it('should include props as args query param in URL', async () => { + const request = { + jsonrpc: '2.0' as const, + id: 1, + method: 'tools/call', + params: { + name: PREVIEW_STORIES_TOOL_NAME, + arguments: { + stories: [ + { + exportName: 'Primary', + absoluteStoryPath: `${process.cwd()}/src/Button.stories.tsx`, + props: { + label: 'Custom Label', + disabled: true, + }, + }, + ], + }, + }, + }; + + const response = await server.receive(request, { + sessionId: 'test-session', + custom: testContext, + }); + + expect(response.result?.structuredContent?.stories[0]).toEqual({ + title: 'Button', + name: 'Primary', + previewUrl: + 'http://localhost:6006/?path=/story/button--primary&args=label:Custom+Label;disabled:!true', + }); + }); + + it('should include globals query param in URL', async () => { + const request = { + jsonrpc: '2.0' as const, + id: 1, + method: 'tools/call', + params: { + name: PREVIEW_STORIES_TOOL_NAME, + arguments: { + stories: [ + { + exportName: 'Primary', + absoluteStoryPath: `${process.cwd()}/src/Button.stories.tsx`, + globals: { + theme: 'dark', + locale: 'fr', + }, + }, + ], + }, + }, + }; + + const response = await server.receive(request, { + sessionId: 'test-session', + custom: testContext, + }); + + expect(response.result?.structuredContent?.stories[0]).toEqual({ + title: 'Button', + name: 'Primary', + previewUrl: + 'http://localhost:6006/?path=/story/button--primary&globals=theme:dark;locale:fr', + }); + }); + + it('should include both props and globals query params in URL', async () => { + const request = { + jsonrpc: '2.0' as const, + id: 1, + method: 'tools/call', + params: { + name: PREVIEW_STORIES_TOOL_NAME, + arguments: { + stories: [ + { + exportName: 'Primary', + absoluteStoryPath: `${process.cwd()}/src/Button.stories.tsx`, + props: { + label: 'Dark Mode Button', + }, + globals: { + theme: 'dark', + }, + }, + ], + }, + }, + }; + + const response = await server.receive(request, { + sessionId: 'test-session', + custom: testContext, + }); + + expect(response.result?.structuredContent?.stories[0]).toEqual({ + title: 'Button', + name: 'Primary', + previewUrl: + 'http://localhost:6006/?path=/story/button--primary&args=label:Dark+Mode+Button&globals=theme:dark', + }); + }); }); diff --git a/packages/addon-mcp/src/tools/preview-stories.ts b/packages/addon-mcp/src/tools/preview-stories.ts new file mode 100644 index 00000000..c002bbba --- /dev/null +++ b/packages/addon-mcp/src/tools/preview-stories.ts @@ -0,0 +1,197 @@ +import type { McpServer } from 'tmcp'; +import path from 'node:path'; +import url from 'node:url'; +import { storyNameFromExport } from 'storybook/internal/csf'; +import { logger } from 'storybook/internal/node-logger'; +import * as v from 'valibot'; +import { collectTelemetry } from '../telemetry.ts'; +import { buildArgsParam } from '../utils/build-args-param.ts'; +import { fetchStoryIndex } from '../utils/fetch-story-index.ts'; +import { errorToMCPContent } from '../utils/errors.ts'; +import type { AddonContext } from '../types.ts'; +import { StoryInput, StoryInputArray } from '../types.ts'; +import appTemplate from './preview-stories/preview-stories-app-template.html'; +import fs from 'node:fs/promises'; + +export const PREVIEW_STORIES_TOOL_NAME = 'preview-stories'; +export const PREVIEW_STORIES_RESOURCE_URI = `ui://${PREVIEW_STORIES_TOOL_NAME}/preview.html`; + +const PreviewStoriesInput = v.object({ + stories: StoryInputArray, +}); + +const PreviewStoriesOutput = v.object({ + stories: v.array( + v.union([ + v.object({ + title: v.string(), + name: v.string(), + previewUrl: v.string(), + }), + v.object({ + input: StoryInput, + error: v.string(), + }), + ]), + ), +}); + +type PreviewStoriesInput = v.InferOutput; +export type PreviewStoriesOutput = v.InferOutput; + +export async function addPreviewStoriesTool( + server: McpServer, +) { + const previewStoryAppScript = await fs.readFile( + url.fileURLToPath( + import.meta.resolve( + '@storybook/addon-mcp/internal/preview-stories-app-script', + ), + ), + 'utf-8', + ); + + const appHtml = appTemplate.replace( + '// APP_SCRIPT_PLACEHOLDER', + previewStoryAppScript, + ); + server.resource( + { + name: PREVIEW_STORIES_RESOURCE_URI, + description: 'App resource for the Preview Stories tool', + uri: PREVIEW_STORIES_RESOURCE_URI, + //@ts-expect-error tmcp types doesn't know this is valid + mimeType: 'text/html;profile=mcp-app', + }, + () => { + const origin = server.ctx.custom!.origin; + return { + contents: [ + { + uri: PREVIEW_STORIES_RESOURCE_URI, + mimeType: 'text/html;profile=mcp-app', + text: appHtml, + _meta: { + ui: { + prefersBorder: false, + domain: origin, + csp: { + connectDomains: [origin], + resourceDomains: [origin], + frameDomains: [origin], + baseUriDomains: [origin], + }, + }, + }, + }, + ], + }; + }, + ); + + server.tool( + { + name: PREVIEW_STORIES_TOOL_NAME, + title: 'Preview stories', + description: `Use this tool to preview one or more stories, rendering them as an MCP App using the UI Resource or returning the raw URL for users to visit.`, + schema: PreviewStoriesInput, + outputSchema: PreviewStoriesOutput, + enabled: () => server.ctx.custom?.toolsets?.dev ?? true, + _meta: { ui: { resourceUri: PREVIEW_STORIES_RESOURCE_URI } }, + }, + async (input) => { + try { + const { origin, disableTelemetry } = server.ctx.custom ?? {}; + + if (!origin) { + throw new Error('Origin is required in addon context'); + } + + const index = await fetchStoryIndex(origin); + const entriesList = Object.values(index.entries); + + const structuredResult: PreviewStoriesOutput['stories'] = []; + const textResult: string[] = []; + + for (const inputParams of input.stories) { + const { exportName, explicitStoryName, absoluteStoryPath } = + inputParams; + const relativePath = `./${path.relative(process.cwd(), absoluteStoryPath)}`; + + logger.debug('Searching for:'); + logger.debug({ + exportName, + explicitStoryName, + absoluteStoryPath, + relativePath, + }); + + const foundStory = entriesList.find( + (entry) => + entry.importPath === relativePath && + [explicitStoryName, storyNameFromExport(exportName)].includes( + entry.name, + ), + ); + + if (foundStory) { + logger.debug(`Found story ID: ${foundStory.id}`); + let previewUrl = `${origin}/?path=/story/${foundStory.id}`; + + // Add props as args query param if provided + const argsParam = buildArgsParam(inputParams.props ?? {}); + if (argsParam) { + previewUrl += `&args=${argsParam}`; + } + + // Add globals query param if provided + const globalsParam = buildArgsParam(inputParams.globals ?? {}); + if (globalsParam) { + previewUrl += `&globals=${globalsParam}`; + } + + structuredResult.push({ + title: foundStory.title, + name: foundStory.name, + previewUrl, + }); + textResult.push(previewUrl); + } else { + logger.debug('No story found'); + let errorMessage = `No story found for export name "${exportName}" with absolute file path "${absoluteStoryPath}"`; + if (!explicitStoryName) { + errorMessage += ` (did you forget to pass the explicit story name?)`; + } + structuredResult.push({ + input: inputParams, + error: errorMessage, + }); + textResult.push(errorMessage); + } + } + + if (!disableTelemetry) { + await collectTelemetry({ + event: 'tool:previewStories', + server, + toolset: 'dev', + inputStoryCount: input.stories.length, + outputStoryCount: structuredResult.length, + }); + } + + return { + content: textResult.map((text) => ({ + type: 'text', + text, + })), + structuredContent: { + stories: structuredResult, + }, + }; + } catch (error) { + return errorToMCPContent(error); + } + }, + ); +} diff --git a/packages/addon-mcp/src/tools/preview-stories/preview-stories-app-script.ts b/packages/addon-mcp/src/tools/preview-stories/preview-stories-app-script.ts new file mode 100644 index 00000000..289f023b --- /dev/null +++ b/packages/addon-mcp/src/tools/preview-stories/preview-stories-app-script.ts @@ -0,0 +1,237 @@ +// Adapted from https://github.com/MCP-UI-Org/mcp-ui/blob/fd89e2942eb7148d83245397be0b6ad34ce538b0/sdks/typescript/server/src/adapters/mcp-apps/adapter-runtime.ts +/** + * Current protocol version - must match LATEST_PROTOCOL_VERSION from ext-apps + * @see https://github.com/modelcontextprotocol/ext-apps + */ +const LATEST_PROTOCOL_VERSION = '2025-11-21'; + +import { MCP_APP_SIZE_CHANGED_EVENT, MCP_APP_PARAM } from '../../constants.ts'; +import type { PreviewStoriesOutput } from '../preview-stories.ts'; +import pkg from '../../../package.json' with { type: 'json' }; + +interface McpUiHostStyles { + variables?: Record; + css?: { + fonts?: string; + }; +} + +interface McpUiHostContext { + [key: string]: unknown; + theme?: 'light' | 'dark'; + styles?: McpUiHostStyles; + displayMode?: 'inline' | 'fullscreen' | 'pip'; + availableDisplayModes?: string[]; + locale?: string; + timeZone?: string; + userAgent?: string; + platform?: 'web' | 'desktop' | 'mobile'; + deviceCapabilities?: { + touch?: boolean; + hover?: boolean; + }; + safeAreaInsets?: { + top: number; + right: number; + bottom: number; + left: number; + }; +} + +interface McpUiInitializeResult { + protocolVersion: string; + hostInfo: { + name: string; + version: string; + }; + hostCapabilities: Record; + hostContext: McpUiHostContext; + [key: string]: unknown; +} + +/** + * MCP Apps SEP protocol method constants + * These match the `method` field values from @modelcontextprotocol/ext-apps type definitions: + * - McpUiInitializeRequest: "ui/initialize" + * - McpUiInitializedNotification: "ui/notifications/initialized" + * - McpUiToolInputNotification: "ui/notifications/tool-input" + * - McpUiToolInputPartialNotification: "ui/notifications/tool-input-partial" + * - McpUiToolResultNotification: "ui/notifications/tool-result" + * - McpUiHostContextChangedNotification: "ui/notifications/host-context-changed" + * - McpUiSizeChangedNotification: "ui/notifications/size-changed" + * - McpUiResourceTeardownRequest: "ui/resource-teardown" + * + * @see https://github.com/modelcontextprotocol/ext-apps/blob/main/src/spec.types.ts + */ +const METHODS = { + // Lifecycle + INITIALIZE: 'ui/initialize', + INITIALIZED: 'ui/notifications/initialized', + + // Tool data (Host -> Guest) + TOOL_INPUT: 'ui/notifications/tool-input', + TOOL_INPUT_PARTIAL: 'ui/notifications/tool-input-partial', + TOOL_RESULT: 'ui/notifications/tool-result', + TOOL_CANCELLED: 'ui/notifications/tool-cancelled', + + // Context & UI + HOST_CONTEXT_CHANGED: 'ui/notifications/host-context-changed', + SIZE_CHANGED: 'ui/notifications/size-changed', + RESOURCE_TEARDOWN: 'ui/resource-teardown', + + // Standard MCP methods + TOOLS_CALL: 'tools/call', + NOTIFICATIONS_MESSAGE: 'notifications/message', + OPEN_LINK: 'ui/open-link', + MESSAGE: 'ui/message', +} as const; + +type McpMethod = (typeof METHODS)[keyof typeof METHODS]; + +// Adapted from https://github.com/modelcontextprotocol/ext-apps/blob/main/specification/draft/apps.mdx#transport-layer + +let nextId = 1; + +function sendHostRequest( + method: McpMethod, + params: unknown, +): Promise { + const id = nextId++; + const { promise, resolve, reject } = + Promise.withResolvers(); + + window.parent.postMessage({ jsonrpc: '2.0', id, method, params }, '*'); + + window.addEventListener('message', function listener(event: MessageEvent) { + if (event.data?.id !== id) { + return; + } + window.removeEventListener('message', listener); + if (event.data?.result) { + resolve(event.data.result); + } else if (event.data?.error) { + reject(new Error(String(event.data.error))); + } + }); + return promise; +} + +function sendHostNotification(method: McpMethod, params: unknown): void { + window.parent.postMessage({ jsonrpc: '2.0', method, params }, '*'); +} + +function onHostNotification( + method: McpMethod, + handler: (params: T) => void, +): void { + window.addEventListener('message', function listener(event: MessageEvent) { + if (event.data?.method === method) { + handler(event.data.params as T); + } + }); +} + +const initializeResult = (await sendHostRequest(METHODS.INITIALIZE, { + appInfo: { + name: 'storybook-story-preview', + version: pkg.version, + }, + appCapabilities: {}, + protocolVersion: LATEST_PROTOCOL_VERSION, +})) as McpUiInitializeResult; +applyHostStyles(initializeResult?.hostContext); + +onHostNotification(METHODS.TOOL_RESULT, loadStoryIframes); +onHostNotification(METHODS.HOST_CONTEXT_CHANGED, applyHostStyles); +sendHostNotification(METHODS.INITIALIZED, {}); + +// Listen for size messages from Storybook iframes (height only to avoid feedback loops) +window.addEventListener('message', function (event: MessageEvent) { + if (event.data?.type !== MCP_APP_SIZE_CHANGED_EVENT) { + return; + } + + // Find the iframe that sent this message + const iframes = document.querySelectorAll('.story-iframe'); + let hasResizedIframes = false; + for (const iframe of iframes) { + if (iframe.contentWindow === event.source) { + iframe.style.height = (event.data.height ?? 0) + 'px'; + hasResizedIframes = true; + break; + } + } + if (hasResizedIframes) { + resizeApp(); + } +}); + +function applyHostStyles(hostContext: McpUiHostContext | undefined): void { + if (hostContext?.theme) { + document.documentElement.setAttribute('data-theme', hostContext.theme); + } + if (!hostContext?.styles?.variables) { + return; + } + for (const [key, value] of Object.entries(hostContext.styles.variables)) { + if (value) { + document.documentElement.style.setProperty(key, value); + } + } + resizeApp(); +} + +function resizeApp(): void { + console.log('Resizing app to fit content', { + width: document.body.scrollWidth, + height: document.body.scrollHeight, + }); + sendHostNotification(METHODS.SIZE_CHANGED, { + width: document.body.scrollWidth, + height: document.body.scrollHeight, + }); +} + +function loadStoryIframes(params: { + structuredContent?: PreviewStoriesOutput; +}): void { + const stories = params.structuredContent?.stories; + + if (!stories || stories.length === 0) { + console.warn('No preview URLs found in tool result.'); + return; + } + + const template = document.getElementById( + 'preview-template', + ) as HTMLTemplateElement; + + for (const storyResult of stories) { + if ('error' in storyResult) { + console.warn('Skipping story with error:', storyResult.error); + continue; + } + const clone = template.content.cloneNode(true) as DocumentFragment; + const article = clone.querySelector('article') as HTMLElement; + const heading = clone.querySelector('h1') as HTMLHeadingElement; + const iframe = clone.querySelector('iframe') as HTMLIFrameElement; + + heading.textContent = `${storyResult.title} - ${storyResult.name}`; + + // Set a reasonable default size while waiting for the iframe to report its size + iframe.style.width = '100%'; + iframe.style.height = '0'; + + const iframeSrc = storyResult.previewUrl.replace( + '/?path=/story/', + '/iframe.html?id=', + ); + // Add MCP App param to enable size reporting in Storybook's preview.ts + const url = new URL(iframeSrc); + url.searchParams.set(MCP_APP_PARAM, 'true'); + iframe.src = url.toString(); + + document.body.appendChild(article); + } + resizeApp(); +} diff --git a/packages/addon-mcp/src/tools/preview-stories/preview-stories-app-template.html b/packages/addon-mcp/src/tools/preview-stories/preview-stories-app-template.html new file mode 100644 index 00000000..9dbf2669 --- /dev/null +++ b/packages/addon-mcp/src/tools/preview-stories/preview-stories-app-template.html @@ -0,0 +1,72 @@ + + + + + + + + + + + diff --git a/packages/addon-mcp/src/types.ts b/packages/addon-mcp/src/types.ts index 4739f1ef..3c92bf37 100644 --- a/packages/addon-mcp/src/types.ts +++ b/packages/addon-mcp/src/types.ts @@ -1,6 +1,7 @@ import * as v from 'valibot'; import type { Options } from 'storybook/internal/types'; import type { StorybookContext } from '@storybook/mcp'; +import { GET_UI_BUILDING_INSTRUCTIONS_TOOL_NAME } from './tools/get-storybook-story-instructions'; export const AddonOptions = v.object({ toolsets: v.optional( @@ -59,12 +60,37 @@ export const StoryInput = v.object({ * Optional explicit story name if different from the export name. * This is used when a story has a custom name defined. */ - explicitStoryName: v.optional(v.string()), + explicitStoryName: v.pipe( + v.optional(v.string()), + v.description( + `If the story has an explicit name set via the "name" propoerty, that is different from the export name, provide it here. +Otherwise don't set this.`, + ), + ), /** * Absolute file path to the story file. */ absoluteStoryPath: v.string(), + + /** + * Optional props to pass to the story. + */ + props: v.pipe( + v.optional(v.record(v.string(), v.any())), + v.description(`Optional custom props to pass to the story for rendering. Use this when you don't want to render the default story, +but you want to customize some args or other props. +You can look up the component's documentation using the ${GET_UI_BUILDING_INSTRUCTIONS_TOOL_NAME} tool to see what props are available.`), + ), + + /** + * Optional globals to set for the story. + */ + globals: v.pipe( + v.optional(v.record(v.string(), v.any())), + v.description(`Optional Storybook globals to set for the story preview. Globals are used for things like theme, locale, viewport, and other cross-cutting concerns. +Common globals include 'theme' (e.g., 'dark', 'light'), 'locale' (e.g., 'en', 'fr'), and 'backgrounds' (e.g., { value: '#000' }).`), + ), }); export type StoryInput = v.InferOutput; @@ -73,9 +99,3 @@ export type StoryInput = v.InferOutput; */ export const StoryInputArray = v.array(StoryInput); export type StoryInputArray = v.InferOutput; - -/** - * Schema for the output URL array. - */ -export const StoryUrlArray = v.array(v.string()); -export type StoryUrlArray = v.InferOutput; diff --git a/packages/addon-mcp/src/utils/build-args-param.test.ts b/packages/addon-mcp/src/utils/build-args-param.test.ts new file mode 100644 index 00000000..489241b7 --- /dev/null +++ b/packages/addon-mcp/src/utils/build-args-param.test.ts @@ -0,0 +1,151 @@ +import { describe, expect, it } from 'vitest'; +import { buildArgsParam } from './build-args-param.ts'; + +describe('buildArgsParam', () => { + it('returns empty string for empty object', () => { + expect(buildArgsParam({})).toEqual(''); + }); + + it('returns empty string for null/undefined', () => { + expect(buildArgsParam(null as any)).toEqual(''); + expect(buildArgsParam(undefined as any)).toEqual(''); + }); + + it('builds a simple key-value pair', () => { + const param = buildArgsParam({ key: 'val' }); + expect(param).toEqual('key:val'); + }); + + it('builds multiple values', () => { + const param = buildArgsParam({ one: '1', two: '2', three: '3' }); + expect(param).toEqual('one:1;two:2;three:3'); + }); + + it('builds booleans', () => { + const param = buildArgsParam({ yes: true, no: false }); + expect(param).toEqual('yes:!true;no:!false'); + }); + + it('builds numbers', () => { + const param = buildArgsParam({ count: 42, decimal: 3.14 }); + expect(param).toEqual('count:42;decimal:3.14'); + }); + + it('builds arrays', () => { + const param = buildArgsParam({ arr: ['1', '2', '3'] }); + expect(param).toEqual('arr[0]:1;arr[1]:2;arr[2]:3'); + }); + + it('builds sparse arrays', () => { + // eslint-disable-next-line no-sparse-arrays + const param = buildArgsParam({ arr: ['1', , '3'] }); + expect(param).toEqual('arr[0]:1;arr[2]:3'); + }); + + it('builds simple objects', () => { + const param = buildArgsParam({ obj: { one: '1', two: '2' } }); + expect(param).toEqual('obj.one:1;obj.two:2'); + }); + + it('builds nested objects', () => { + const param = buildArgsParam({ + obj: { foo: { one: '1', two: '2' }, bar: { one: '1' } }, + }); + expect(param).toEqual('obj.foo.one:1;obj.foo.two:2;obj.bar.one:1'); + }); + + it('builds arrays in objects', () => { + // eslint-disable-next-line no-sparse-arrays + const param = buildArgsParam({ obj: { foo: ['1', , '3'] } }); + expect(param).toEqual('obj.foo[0]:1;obj.foo[2]:3'); + }); + + it('builds single object in array', () => { + const param = buildArgsParam({ arr: [{ one: '1', two: '2' }] }); + expect(param).toEqual('arr[0].one:1;arr[0].two:2'); + }); + + it('builds multiple objects in array', () => { + const param = buildArgsParam({ arr: [{ one: '1' }, { two: '2' }] }); + expect(param).toEqual('arr[0].one:1;arr[1].two:2'); + }); + + it('builds nested object in array', () => { + const param = buildArgsParam({ arr: [{ foo: { bar: 'val' } }] }); + expect(param).toEqual('arr[0].foo.bar:val'); + }); + + it('encodes space as +', () => { + const param = buildArgsParam({ key: 'foo bar baz' }); + expect(param).toEqual('key:foo+bar+baz'); + }); + + it('encodes null values as !null', () => { + const param = buildArgsParam({ key: null }); + expect(param).toEqual('key:!null'); + }); + + it('encodes undefined values as !undefined', () => { + const param = buildArgsParam({ key: undefined }); + expect(param).toEqual('key:!undefined'); + }); + + it('encodes nested null values as !null', () => { + const param = buildArgsParam({ + foo: { bar: [{ key: null }], baz: null }, + }); + expect(param).toEqual('foo.bar[0].key:!null;foo.baz:!null'); + }); + + it('encodes hex color values as !hex(value)', () => { + const param = buildArgsParam({ key: '#ff4785' }); + expect(param).toEqual('key:!hex(ff4785)'); + }); + + it('encodes short hex color values', () => { + const param = buildArgsParam({ key: '#f47' }); + expect(param).toEqual('key:!hex(f47)'); + }); + + it('encodes 8-digit hex color values with alpha', () => { + const param = buildArgsParam({ key: '#ff478580' }); + expect(param).toEqual('key:!hex(ff478580)'); + }); + + it('encodes rgba color values by prefixing and compacting', () => { + const param = buildArgsParam({ + rgb: 'rgb(255, 71, 133)', + rgba: 'rgba(255, 71, 133, 0.5)', + }); + expect(param).toEqual('rgb:!rgb(255,71,133);rgba:!rgba(255,71,133,0.5)'); + }); + + it('encodes hsla color values by prefixing and compacting', () => { + const param = buildArgsParam({ + hsl: 'hsl(45, 99%, 70%)', + hsla: 'hsla(45, 99%, 70%, 0.5)', + }); + expect(param).toEqual('hsl:!hsl(45,99,70);hsla:!hsla(45,99,70,0.5)'); + }); + + it('encodes Date objects as !date(ISO string)', () => { + const param = buildArgsParam({ + key: new Date('2001-02-03T04:05:06.789Z'), + }); + expect(param).toEqual('key:!date(2001-02-03T04:05:06.789Z)'); + }); + + it('handles mixed types', () => { + const param = buildArgsParam({ + str: 'hello', + num: 42, + bool: true, + nil: null, + arr: [1, 2], + obj: { nested: 'value' }, + }); + expect(param).toEqual( + 'str:hello;num:42;bool:!true;nil:!null;arr[0]:1;arr[1]:2;obj.nested:value', + ); + }); +}); diff --git a/packages/addon-mcp/src/utils/build-args-param.ts b/packages/addon-mcp/src/utils/build-args-param.ts new file mode 100644 index 00000000..888dc171 --- /dev/null +++ b/packages/addon-mcp/src/utils/build-args-param.ts @@ -0,0 +1,107 @@ +/* +This file is adapted from Storybook's own implementation: +https://github.com/storybookjs/storybook/blob/466824f7d57bfed34e0096671602333bf85c86bc/code/core/src/router/utils.test.ts +Just simplified a bit for our use case. +*/ +import { stringify } from 'picoquery'; + +type Args = Record; + +const HEX_REGEXP = /^#([a-f0-9]{3,4}|[a-f0-9]{6}|[a-f0-9]{8})$/i; +const COLOR_REGEXP = + /^(rgba?|hsla?)\(([0-9]{1,3}),\s?([0-9]{1,3})%?,\s?([0-9]{1,3})%?,?\s?([0-9](\.[0-9]{1,2})?)?\)$/i; + +/** + * Encodes special values for Storybook's args URL format. + * Handles undefined, null, booleans, dates, hex colors, and rgba/hsla colors. + */ +function encodeSpecialValues(value: unknown): unknown { + if (value === undefined) { + return '!undefined'; + } + + if (value === null) { + return '!null'; + } + + if (typeof value === 'string') { + if (HEX_REGEXP.test(value)) { + return `!hex(${value.slice(1)})`; + } + + if (COLOR_REGEXP.test(value)) { + return `!${value.replace(/[\s%]/g, '')}`; + } + return value; + } + + if (typeof value === 'boolean') { + return `!${value}`; + } + + if (value instanceof Date) { + return `!date(${value.toISOString()})`; + } + + if (Array.isArray(value)) { + return value.map(encodeSpecialValues); + } + + // is object + if (typeof value === 'object' && value !== null) { + return Object.entries(value as Record).reduce( + (acc, [key, val]) => + Object.assign(acc, { [key]: encodeSpecialValues(val) }), + {}, + ); + } + + return value; +} + +/** + * Replaces some url-encoded characters with their decoded equivalents. + * The URI RFC specifies these should be encoded, but all browsers will + * tolerate them being decoded, so we opt to go with it for cleaner looking URIs. + */ +function decodeKnownQueryChar(chr: string): string { + switch (chr) { + case '%20': + return '+'; + case '%5B': + return '['; + case '%5D': + return ']'; + case '%2C': + return ','; + case '%3A': + return ':'; + } + return chr; +} + +const KNOWN_QUERY_CHAR_REGEXP = /%[0-9A-F]{2}/g; + +/** + * Builds a Storybook args query parameter string from an object of props. + * + * The format uses semicolons as delimiters and colons for key:value pairs, + * with special encoding for booleans, null, undefined, dates, and colors. + * + * Example output: "disabled:!true;label:Hello+World;count:42" + */ +export function buildArgsParam(args: Args): string { + if (!args || Object.keys(args).length === 0) { + return ''; + } + + return stringify(encodeSpecialValues(args), { + delimiter: ';', + nesting: true, + nestingSyntax: 'js', + }) + .replace(KNOWN_QUERY_CHAR_REGEXP, decodeKnownQueryChar) + .split(';') + .map((part: string) => part.replace('=', ':')) + .join(';'); +} diff --git a/packages/addon-mcp/tsdown.config.ts b/packages/addon-mcp/tsdown.config.ts index 0e953e99..38efe4ac 100644 --- a/packages/addon-mcp/tsdown.config.ts +++ b/packages/addon-mcp/tsdown.config.ts @@ -2,7 +2,27 @@ import { defineConfig } from 'tsdown'; import sharedTsDownConfig from '../../tsdown-shared.config.ts'; import pkg from './package.json' with { type: 'json' }; -export default defineConfig({ +const sharedNodeConfig = sharedTsDownConfig(pkg.name); +const browserConfig = { ...sharedTsDownConfig(pkg.name), - entry: 'src/preset.ts', -}); + target: 'chrome131', +}; +export default defineConfig([ + { + ...sharedNodeConfig, + entry: 'src/preset.ts', + }, + { + ...browserConfig, + entry: 'src/preview.ts', + }, + /* + this must be a separate config because it can't rely on code splitting at all. + Using a shared config would risk code being shared between entries + which would break the MCP App script + */ + { + ...browserConfig, + entry: 'src/tools/preview-stories/preview-stories-app-script.ts', + }, +]); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9a8f8312..d8f6b6c5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -6,36 +6,21 @@ settings: catalogs: default: - '@storybook/addon-a11y': - specifier: 10.2.0-alpha.14 - version: 10.2.0-alpha.14 - '@storybook/addon-docs': - specifier: 10.2.0-alpha.14 - version: 10.2.0-alpha.14 - '@storybook/react-vite': - specifier: 10.2.0-alpha.14 - version: 10.2.0-alpha.14 '@tmcp/adapter-valibot': specifier: ^0.1.4 version: 0.1.4 '@tmcp/transport-http': specifier: ^0.8.0 version: 0.8.0 - '@tmcp/transport-stdio': - specifier: ^0.4.1 - version: 0.4.1 storybook: - specifier: 10.2.0-alpha.14 - version: 10.2.0-alpha.14 + specifier: 10.3.0-alpha.0 + version: 10.3.0-alpha.0 tmcp: specifier: ^1.16.0 version: 1.18.1 valibot: specifier: 1.2.0 version: 1.2.0 - vite: - specifier: 7.2.2 - version: 7.2.2 importers: @@ -100,19 +85,22 @@ importers: version: 5.1.4(typescript@5.9.3)(vite@7.2.2(@types/node@20.19.0)(jiti@2.6.1)(less@4.4.2)(terser@5.44.0)) vitest: specifier: 4.0.6 - version: 4.0.6(@types/node@20.19.0)(@vitest/browser-playwright@4.0.6)(jiti@2.6.1)(less@4.4.2)(msw@2.12.7(@types/node@20.19.0)(typescript@5.9.3))(terser@5.44.0) + version: 4.0.6(@types/node@20.19.0)(@vitest/browser-playwright@4.0.6)(jiti@2.6.1)(jsdom@27.4.0)(less@4.4.2)(msw@2.12.7(@types/node@20.19.0)(typescript@5.9.3))(terser@5.44.0) apps/internal-storybook: devDependencies: '@storybook/addon-docs': specifier: 'catalog:' - version: 10.2.0-alpha.14(@types/react@18.3.26)(esbuild@0.25.12)(rollup@4.52.5)(storybook@10.2.0-alpha.14(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(vite@7.2.2(@types/node@24.10.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.0))(webpack@5.102.1(@swc/core@1.13.5)(esbuild@0.25.12)) + version: 10.3.0-alpha.0(@types/react@18.3.26)(esbuild@0.25.12)(rollup@4.52.5)(storybook@10.3.0-alpha.0(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(vite@7.2.2(@types/node@24.10.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.0))(webpack@5.102.1(@swc/core@1.13.5)(esbuild@0.25.12)) '@storybook/addon-mcp': specifier: workspace:* version: link:../../packages/addon-mcp + '@storybook/addon-themes': + specifier: ^10.2.0 + version: 10.2.0(storybook@10.3.0-alpha.0(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)) '@storybook/react-vite': specifier: 'catalog:' - version: 10.2.0-alpha.14(esbuild@0.25.12)(msw@2.12.7(@types/node@24.10.1)(typescript@5.9.3))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@4.52.5)(storybook@10.2.0-alpha.14(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.9.3)(vite@7.2.2(@types/node@24.10.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.0))(webpack@5.102.1(@swc/core@1.13.5)(esbuild@0.25.12)) + version: 10.3.0-alpha.0(esbuild@0.25.12)(msw@2.12.7(@types/node@24.10.1)(typescript@5.9.3))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@4.52.5)(storybook@10.3.0-alpha.0(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.9.3)(vite@7.2.2(@types/node@24.10.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.0))(webpack@5.102.1(@swc/core@1.13.5)(esbuild@0.25.12)) '@types/react': specifier: ^18.2.65 version: 18.3.26 @@ -130,7 +118,7 @@ importers: version: 18.3.1(react@18.3.1) storybook: specifier: 'catalog:' - version: 10.2.0-alpha.14(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 10.3.0-alpha.0(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) tinyexec: specifier: ^1.0.2 version: 1.0.2 @@ -163,13 +151,13 @@ importers: version: 1.1.11(@types/react-dom@19.2.3(@types/react@18.3.26))(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@storybook/addon-a11y': specifier: 'catalog:' - version: 10.2.0-alpha.14(storybook@10.2.0-alpha.14(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)) + version: 10.3.0-alpha.0(storybook@10.3.0-alpha.0(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)) '@storybook/mcp': specifier: workspace:* version: link:../packages/mcp '@storybook/react-vite': specifier: 'catalog:' - version: 10.2.0-alpha.14(esbuild@0.25.12)(msw@2.12.7(@types/node@24.10.1)(typescript@5.9.3))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(rollup@4.52.5)(storybook@10.2.0-alpha.14(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(typescript@5.9.3)(vite@7.2.2(@types/node@24.10.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.0))(webpack@5.102.1(@swc/core@1.13.5)(esbuild@0.25.12)) + version: 10.3.0-alpha.0(esbuild@0.25.12)(msw@2.12.7(@types/node@24.10.1)(typescript@5.9.3))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(rollup@4.52.5)(storybook@10.3.0-alpha.0(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(typescript@5.9.3)(vite@7.2.2(@types/node@24.10.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.0))(webpack@5.102.1(@swc/core@1.13.5)(esbuild@0.25.12)) '@tsconfig/node-ts': specifier: ^23.6.1 version: 23.6.2 @@ -241,10 +229,10 @@ importers: version: 5.83.4(react-dom@19.2.0(react@19.2.0))(react@19.2.0) storybook: specifier: 'catalog:' - version: 10.2.0-alpha.14(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 10.3.0-alpha.0(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) storybook-addon-test-codegen: specifier: ^3.0.0 - version: 3.0.0(storybook@10.2.0-alpha.14(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)) + version: 3.0.0(storybook@10.3.0-alpha.0(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)) tinyexec: specifier: ^1.0.1 version: 1.0.2 @@ -269,6 +257,9 @@ importers: '@tmcp/transport-http': specifier: 'catalog:' version: 0.8.0(tmcp@1.18.1(typescript@5.9.3)) + picoquery: + specifier: ^2.5.0 + version: 2.5.0 tmcp: specifier: 'catalog:' version: 1.18.1(typescript@5.9.3) @@ -278,7 +269,7 @@ importers: devDependencies: storybook: specifier: 'catalog:' - version: 10.2.0-alpha.14(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 10.3.0-alpha.0(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) packages/mcp: dependencies: @@ -310,6 +301,9 @@ importers: packages: + '@acemir/cssom@0.9.31': + resolution: {integrity: sha512-ZnR3GSaH+/vJ0YlHau21FjfLYjMpYVIzTD8M8vIEQvIGxeOXyXdzCI140rrCY862p/C/BbzWsjc1dgnM9mkoTA==} + '@actions/core@1.11.1': resolution: {integrity: sha512-hXJCSrkwfA46Vd9Z3q4cpEpHB1rL5NG04+/rbqW9d3+CSvtB1tYe8UTpAlixa1vj0m/ULglfEK2UKxMGxCxv5A==} @@ -334,6 +328,15 @@ packages: peerDependencies: zod: ^3.24.1 + '@asamuzakjp/css-color@4.1.1': + resolution: {integrity: sha512-B0Hv6G3gWGMn0xKJ0txEi/jM5iFpT3MfDxmhZFb4W047GvytCf1DHQ1D69W3zHI4yWe2aTZAA0JnbMZ7Xc8DuQ==} + + '@asamuzakjp/dom-selector@6.7.6': + resolution: {integrity: sha512-hBaJER6A9MpdG3WgdlOolHmbOYvSk46y7IQN/1+iqiCuUu6iWdQrs9DGKF8ocqsEqWujWf/V7b7vaDgiUmIvUg==} + + '@asamuzakjp/nwsapi@2.3.9': + resolution: {integrity: sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==} + '@babel/code-frame@7.27.1': resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} engines: {node: '>=6.9.0'} @@ -518,12 +521,34 @@ packages: '@csstools/css-parser-algorithms': ^3.0.5 '@csstools/css-tokenizer': ^3.0.4 + '@csstools/color-helpers@5.1.0': + resolution: {integrity: sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==} + engines: {node: '>=18'} + + '@csstools/css-calc@2.1.4': + resolution: {integrity: sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==} + engines: {node: '>=18'} + peerDependencies: + '@csstools/css-parser-algorithms': ^3.0.5 + '@csstools/css-tokenizer': ^3.0.4 + + '@csstools/css-color-parser@3.1.0': + resolution: {integrity: sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==} + engines: {node: '>=18'} + peerDependencies: + '@csstools/css-parser-algorithms': ^3.0.5 + '@csstools/css-tokenizer': ^3.0.4 + '@csstools/css-parser-algorithms@3.0.5': resolution: {integrity: sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==} engines: {node: '>=18'} peerDependencies: '@csstools/css-tokenizer': ^3.0.4 + '@csstools/css-syntax-patches-for-csstree@1.0.25': + resolution: {integrity: sha512-g0Kw9W3vjx5BEBAF8c5Fm2NcB/Fs8jJXh85aXqwEXiL+tqtOut07TWgyaGzAAfTM+gKckrrncyeGEZPcaRgm2Q==} + engines: {node: '>=18'} + '@csstools/css-tokenizer@3.0.4': resolution: {integrity: sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==} engines: {node: '>=18'} @@ -744,6 +769,15 @@ packages: resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@exodus/bytes@1.9.0': + resolution: {integrity: sha512-lagqsvnk09NKogQaN/XrtlWeUF8SRhT12odMvbTIIaVObqzwAogL6jhR4DAp0gPuKoM1AOVrKUshJpRdpMFrww==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + peerDependencies: + '@noble/hashes': ^1.8.0 || ^2.0.0 + peerDependenciesMeta: + '@noble/hashes': + optional: true + '@fastify/busboy@2.1.1': resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==} engines: {node: '>=14'} @@ -2061,28 +2095,33 @@ packages: '@standard-schema/spec@1.0.0': resolution: {integrity: sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==} - '@storybook/addon-a11y@10.2.0-alpha.14': - resolution: {integrity: sha512-RdW2P3QLta8p4FGrQZWrcgdhuyA6PqoLVQ1Xr+hOOYDkO1Zhr1KgcoGDYtGYM0GMm//Z40dLkYkqYPWCs4g2pg==} + '@storybook/addon-a11y@10.3.0-alpha.0': + resolution: {integrity: sha512-8wWV0y2XSuJLlYBlaJc3X0wO4MpkoTcnZzPElgI8vvq55o3ip019ChyQ7YDZuCxyg/uGJQEOInDkIprkGl9YFw==} + peerDependencies: + storybook: ^10.3.0-alpha.0 + + '@storybook/addon-docs@10.3.0-alpha.0': + resolution: {integrity: sha512-vjZ7Zh1ve7PBhF9Rk8xEOQD2AGrnWW1oHpVnXcX+KMdFEuivlxwJFF6K07Skoh1fRrBGHN1D5/4SOTYNFs+Wlg==} peerDependencies: - storybook: ^10.2.0-alpha.14 + storybook: ^10.3.0-alpha.0 - '@storybook/addon-docs@10.2.0-alpha.14': - resolution: {integrity: sha512-4kQUfHk2uxrEfLVYyE5N7f94K33iWqIRUfxRd+NhT+SUwJkVHPQ8BqQ29Z9qwJ7RO6otAH2RwZO/BmZBqTgECA==} + '@storybook/addon-themes@10.2.0': + resolution: {integrity: sha512-BJsBvxqMtBcZYKVOt0S8NRMAeOBXND5mtOr3ga7jRXDGMP6/BbFo/SBJ1QKjRTsXw/rsOfm6MKWc4jwgbuj4Nw==} peerDependencies: - storybook: ^10.2.0-alpha.14 + storybook: ^10.2.0 - '@storybook/builder-vite@10.2.0-alpha.14': - resolution: {integrity: sha512-PZQ0oSVSfKaGe+h48MSGoH3wmcYRPbcmuX8G7GLORViW+x7gILLr0e3D5MF5C9rc4BHpfxikaXa3Gq5krUYeKQ==} + '@storybook/builder-vite@10.3.0-alpha.0': + resolution: {integrity: sha512-3dI0Z+2/1/wTrbWmp4DMH30qJ8yFo4OWq5gwUm/dUCOwHKmQKMUgr7i26OLuG6itQIhrsHfhOlnsb5FDBSXgLg==} peerDependencies: - storybook: ^10.2.0-alpha.14 + storybook: ^10.3.0-alpha.0 vite: ^5.0.0 || ^6.0.0 || ^7.0.0 - '@storybook/csf-plugin@10.2.0-alpha.14': - resolution: {integrity: sha512-uACCM01OIzeBPOFeNDygxjIqLTlYDQHpzVvMveRz8kcHrP+1jOi6Cq5efMXMmmtb2ltwhr39bblkqLcZCz0lkg==} + '@storybook/csf-plugin@10.3.0-alpha.0': + resolution: {integrity: sha512-o+hvAcvl3iHIem5tbSwgTKKiduu17TST/IHejSfka9NJ6c5EKsCSngDSLafoSlg573h2TsSJLKgeE8w/yLnWfg==} peerDependencies: esbuild: '*' rollup: '*' - storybook: ^10.2.0-alpha.14 + storybook: ^10.3.0-alpha.0 vite: '*' webpack: '*' peerDependenciesMeta: @@ -2104,27 +2143,27 @@ packages: 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/react-dom-shim@10.2.0-alpha.14': - resolution: {integrity: sha512-QXIfC1XF1wRV2Y3/K7+yhqNUiWkStixk08SNOQ83RUI8ULzKb4GltRHyvt16gjQHHp+8LB5duV6PY8GI/3Il2g==} + '@storybook/react-dom-shim@10.3.0-alpha.0': + resolution: {integrity: sha512-Dfu1Z3FcvdF2mm6uGUjd5Rk7MFRrGkTrUT0Wxt2EHbzjHE28bOu7Eb3eKvXAtrDwuRCiC2IVbdxx2qu1Q/kjqA==} 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.2.0-alpha.14 + storybook: ^10.3.0-alpha.0 - '@storybook/react-vite@10.2.0-alpha.14': - resolution: {integrity: sha512-mrT0kUObQwc4G73f8FKEXdvPT1cZ/iORW8S7KrIyeV83u0FcMPxHcZcYGLIfdvpOgLNRBK6pCSadIKLV5pOD6w==} + '@storybook/react-vite@10.3.0-alpha.0': + resolution: {integrity: sha512-/A8asJLWMQEbeuC5Ux0CRTpDOWLppNNhf1kpM9ZpZv2ZfblDL+dJNEkS9TrsMhGqBc5mpBq7MZF9R83yTg47vA==} 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.2.0-alpha.14 + storybook: ^10.3.0-alpha.0 vite: ^5.0.0 || ^6.0.0 || ^7.0.0 - '@storybook/react@10.2.0-alpha.14': - resolution: {integrity: sha512-IsBgaa+3Erluy5asRTwxZcMeSfo9x8TVuixUXd3LTOpdbi5rjgF7MrEDyNe8oDnxH4vEiQnX59QzMaMZ7CDZmw==} + '@storybook/react@10.3.0-alpha.0': + resolution: {integrity: sha512-g2mKx+n2UBQNWnjRjesQ8WrBu8PVIfOgv8fvQOJkiIgOrAZeDOcriMSdmJBnGLLdYXf92TfD7Ose78IodOTW8Q==} 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.2.0-alpha.14 + storybook: ^10.3.0-alpha.0 typescript: '>= 4.9.x' peerDependenciesMeta: typescript: @@ -2523,6 +2562,10 @@ packages: engines: {node: '>=0.4.0'} hasBin: true + agent-base@7.1.4: + resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} + engines: {node: '>= 14'} + ai-tokenizer@1.0.6: resolution: {integrity: sha512-GaakQFxen0pRH/HIA4v68ZM40llCH27HUYUSBLK+gVuZ57e53pYJe1xFvSTj4sJJjbWU92m1X6NjPWyeWkFDow==} peerDependencies: @@ -2643,6 +2686,9 @@ packages: resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==} engines: {node: '>=4'} + bidi-js@1.0.3: + resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==} + birpc@2.8.0: resolution: {integrity: sha512-Bz2a4qD/5GRhiHSwj30c/8kC8QGj12nNDwz3D4ErQ4Xhy35dsSDvF+RA/tWpjyU0pdGtSDiEk6B5fBGE1qNVhw==} @@ -2922,6 +2968,10 @@ packages: resolution: {integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==} engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} + cssstyle@5.3.7: + resolution: {integrity: sha512-7D2EPVltRrsTkhpQmksIu+LxeWAIEk6wRDMJ1qljlv+CKHJM+cJLlfhWIzNA44eAsHXSNe3+vO6DW1yCYx8SuQ==} + engines: {node: '>=20'} + csstype@3.1.3: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} @@ -2936,6 +2986,10 @@ packages: resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} engines: {node: '>= 12'} + data-urls@6.0.1: + resolution: {integrity: sha512-euIQENZg6x8mj3fO6o9+fOW8MimUI4PpD/fZBhJfeioZVy9TUpM4UY7KjQNVZFlqwJ0UdzRDzkycB997HEq1BQ==} + engines: {node: '>=20'} + dataloader@1.4.0: resolution: {integrity: sha512-68s5jYdlvasItOJnCuI2Q9s4q98g0pCyL3HrcKJu8KNugUl8ahgmZYg38ysLTgQjjXX3H8CJLkAvWrclWfcalw==} @@ -2952,6 +3006,9 @@ packages: supports-color: optional: true + decimal.js@10.6.0: + resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} + decode-named-character-reference@1.2.0: resolution: {integrity: sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q==} @@ -3086,6 +3143,10 @@ packages: resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} engines: {node: '>=0.12'} + entities@6.0.1: + resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} + engines: {node: '>=0.12'} + envinfo@7.20.0: resolution: {integrity: sha512-+zUomDcLXsVkQ37vUqWBvQwLaLlj8eZPSi61llaEFAVBY5mhcXdaSw1pSJVl4yTYD5g/gEfpNl28YYk4IPvrrg==} engines: {node: '>=4'} @@ -3428,6 +3489,10 @@ packages: hookable@5.5.3: resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==} + html-encoding-sniffer@6.0.0: + resolution: {integrity: sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + html-escaper@2.0.2: resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} @@ -3435,6 +3500,14 @@ packages: resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} engines: {node: '>= 0.8'} + http-proxy-agent@7.0.2: + resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} + engines: {node: '>= 14'} + + https-proxy-agent@7.0.6: + resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} + engines: {node: '>= 14'} + human-id@4.1.2: resolution: {integrity: sha512-v/J+4Z/1eIJovEBdlV5TYj1IR+ZiohcYGRY+qN/oC9dAfKzVT023N/Bgw37hrKCoVRBvk3bqyzpr2PP5YeTMSg==} hasBin: true @@ -3520,6 +3593,9 @@ packages: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} + is-potential-custom-element-name@1.0.1: + resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} + is-promise@4.0.0: resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} @@ -3587,6 +3663,15 @@ packages: resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} hasBin: true + jsdom@27.4.0: + resolution: {integrity: sha512-mjzqwWRD9Y1J1KUi7W97Gja1bwOOM5Ug0EZ6UDK3xS7j7mndrkwozHtSblfomlzyB4NepioNt+B2sOSzczVgtQ==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + peerDependencies: + canvas: ^3.0.0 + peerDependenciesMeta: + canvas: + optional: true + jsesc@3.1.0: resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} engines: {node: '>=6'} @@ -3959,6 +4044,9 @@ packages: resolution: {integrity: sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==} engines: {node: '>= 0.10'} + parse5@8.0.0: + resolution: {integrity: sha512-9m4m5GSgXjL4AjumKzq1Fgfp3Z8rsvjRNbnkVwfu2ImRqE5D0LnY2QfDen18FSY9C573YU5XxSapdHZTZ2WolA==} + parseurl@1.3.3: resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} engines: {node: '>= 0.8'} @@ -4012,6 +4100,9 @@ packages: resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} engines: {node: '>=12'} + picoquery@2.5.0: + resolution: {integrity: sha512-j1kgOFxtaCyoFCkpoYG2Oj3OdGakadO7HZ7o5CqyRazlmBekKhbDoUnNnXASE07xSY4nDImWZkrZv7toSxMi/g==} + pify@4.0.1: resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} engines: {node: '>=6'} @@ -4543,6 +4634,10 @@ packages: sax@1.4.3: resolution: {integrity: sha512-yqYn1JhPczigF94DMS+shiDMjDowYO6y9+wB/4WgO0Y19jWYk0lQ4tuG5KI7kj4FTp1wxPj5IFfcrz/s1c3jjQ==} + saxes@6.0.0: + resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} + engines: {node: '>=v12.22.7'} + scheduler@0.23.2: resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} @@ -4686,8 +4781,8 @@ packages: peerDependencies: storybook: ^10.0.0 - storybook@10.2.0-alpha.14: - resolution: {integrity: sha512-ZyGO3qVK1ARL08nyVSpb88k8KGIJTJ62nsVNdUCTeyDct/0G7OXFS3F/Ogk5o0EAAS3iymVBKnX/76v/PH3keA==} + storybook@10.3.0-alpha.0: + resolution: {integrity: sha512-I91sdhrGosg7dEkr+oxubV4o5N5ytJd9Q3HhDtWPvzFuBlhoBzeizBQ6t1RnYwbVCQISorPoG8SKxSwMRTUF4w==} hasBin: true peerDependencies: prettier: ^2 || ^3 @@ -4757,6 +4852,9 @@ packages: engines: {node: '>=16'} hasBin: true + symbol-tree@3.2.4: + resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} + tagged-tag@1.0.0: resolution: {integrity: sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==} engines: {node: '>=20'} @@ -4851,6 +4949,10 @@ packages: tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + tr46@6.0.0: + resolution: {integrity: sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==} + engines: {node: '>=20'} + tree-kill@1.2.2: resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} hasBin: true @@ -5171,6 +5273,10 @@ packages: jsdom: optional: true + w3c-xmlserializer@5.0.0: + resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} + engines: {node: '>=18'} + watchpack@2.4.4: resolution: {integrity: sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA==} engines: {node: '>=10.13.0'} @@ -5182,6 +5288,10 @@ packages: webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + webidl-conversions@8.0.1: + resolution: {integrity: sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==} + engines: {node: '>=20'} + webpack-sources@3.3.3: resolution: {integrity: sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==} engines: {node: '>=10.13.0'} @@ -5199,6 +5309,18 @@ packages: webpack-cli: optional: true + whatwg-mimetype@4.0.0: + resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} + engines: {node: '>=18'} + + whatwg-mimetype@5.0.0: + resolution: {integrity: sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==} + engines: {node: '>=20'} + + whatwg-url@15.1.0: + resolution: {integrity: sha512-2ytDk0kiEj/yu90JOAp44PVPUkO9+jVhyf+SybKlRHSDlvOOZhdPIrr7xTH64l4WixO2cP+wQIcgujkGBPPz6g==} + engines: {node: '>=20'} + whatwg-url@5.0.0: resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} @@ -5247,6 +5369,13 @@ packages: resolution: {integrity: sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==} engines: {node: '>=18'} + xml-name-validator@5.0.0: + resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==} + engines: {node: '>=18'} + + xmlchars@2.2.0: + resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} + y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} @@ -5288,6 +5417,9 @@ packages: snapshots: + '@acemir/cssom@0.9.31': + optional: true + '@actions/core@1.11.1': dependencies: '@actions/exec': 1.1.1 @@ -5327,6 +5459,27 @@ snapshots: '@img/sharp-linux-x64': 0.33.5 '@img/sharp-win32-x64': 0.33.5 + '@asamuzakjp/css-color@4.1.1': + dependencies: + '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) + '@csstools/css-color-parser': 3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) + '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) + '@csstools/css-tokenizer': 3.0.4 + lru-cache: 11.2.4 + optional: true + + '@asamuzakjp/dom-selector@6.7.6': + dependencies: + '@asamuzakjp/nwsapi': 2.3.9 + bidi-js: 1.0.3 + css-tree: 3.1.0 + is-potential-custom-element-name: 1.0.1 + lru-cache: 11.2.4 + optional: true + + '@asamuzakjp/nwsapi@2.3.9': + optional: true + '@babel/code-frame@7.27.1': dependencies: '@babel/helper-validator-identifier': 7.28.5 @@ -5641,10 +5794,30 @@ snapshots: '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) '@csstools/css-tokenizer': 3.0.4 + '@csstools/color-helpers@5.1.0': + optional: true + + '@csstools/css-calc@2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)': + dependencies: + '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) + '@csstools/css-tokenizer': 3.0.4 + optional: true + + '@csstools/css-color-parser@3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)': + dependencies: + '@csstools/color-helpers': 5.1.0 + '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) + '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) + '@csstools/css-tokenizer': 3.0.4 + optional: true + '@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4)': dependencies: '@csstools/css-tokenizer': 3.0.4 + '@csstools/css-syntax-patches-for-csstree@1.0.25': + optional: true + '@csstools/css-tokenizer@3.0.4': {} '@csstools/media-query-list-parser@4.0.3(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)': @@ -5796,6 +5969,9 @@ snapshots: '@eslint/core': 0.17.0 levn: 0.4.1 + '@exodus/bytes@1.9.0': + optional: true + '@fastify/busboy@2.1.1': {} '@floating-ui/core@1.7.3': @@ -7560,21 +7736,21 @@ snapshots: '@standard-schema/spec@1.0.0': {} - '@storybook/addon-a11y@10.2.0-alpha.14(storybook@10.2.0-alpha.14(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))': + '@storybook/addon-a11y@10.3.0-alpha.0(storybook@10.3.0-alpha.0(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))': dependencies: '@storybook/global': 5.0.0 axe-core: 4.11.0 - storybook: 10.2.0-alpha.14(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + storybook: 10.3.0-alpha.0(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@storybook/addon-docs@10.2.0-alpha.14(@types/react@18.3.26)(esbuild@0.25.12)(rollup@4.52.5)(storybook@10.2.0-alpha.14(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(vite@7.2.2(@types/node@24.10.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.0))(webpack@5.102.1(@swc/core@1.13.5)(esbuild@0.25.12))': + '@storybook/addon-docs@10.3.0-alpha.0(@types/react@18.3.26)(esbuild@0.25.12)(rollup@4.52.5)(storybook@10.3.0-alpha.0(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(vite@7.2.2(@types/node@24.10.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.0))(webpack@5.102.1(@swc/core@1.13.5)(esbuild@0.25.12))': dependencies: '@mdx-js/react': 3.1.1(@types/react@18.3.26)(react@19.2.0) - '@storybook/csf-plugin': 10.2.0-alpha.14(esbuild@0.25.12)(rollup@4.52.5)(storybook@10.2.0-alpha.14(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(vite@7.2.2(@types/node@24.10.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.0))(webpack@5.102.1(@swc/core@1.13.5)(esbuild@0.25.12)) + '@storybook/csf-plugin': 10.3.0-alpha.0(esbuild@0.25.12)(rollup@4.52.5)(storybook@10.3.0-alpha.0(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(vite@7.2.2(@types/node@24.10.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.0))(webpack@5.102.1(@swc/core@1.13.5)(esbuild@0.25.12)) '@storybook/icons': 2.0.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@storybook/react-dom-shim': 10.2.0-alpha.14(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@10.2.0-alpha.14(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)) + '@storybook/react-dom-shim': 10.3.0-alpha.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@10.3.0-alpha.0(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)) react: 19.2.0 react-dom: 19.2.0(react@19.2.0) - storybook: 10.2.0-alpha.14(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + storybook: 10.3.0-alpha.0(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) ts-dedent: 2.2.0 transitivePeerDependencies: - '@types/react' @@ -7583,11 +7759,16 @@ snapshots: - vite - webpack - '@storybook/builder-vite@10.2.0-alpha.14(esbuild@0.25.12)(msw@2.12.7(@types/node@24.10.1)(typescript@5.9.3))(rollup@4.52.5)(storybook@10.2.0-alpha.14(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(vite@7.2.2(@types/node@24.10.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.0))(webpack@5.102.1(@swc/core@1.13.5)(esbuild@0.25.12))': + '@storybook/addon-themes@10.2.0(storybook@10.3.0-alpha.0(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))': dependencies: - '@storybook/csf-plugin': 10.2.0-alpha.14(esbuild@0.25.12)(rollup@4.52.5)(storybook@10.2.0-alpha.14(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(vite@7.2.2(@types/node@24.10.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.0))(webpack@5.102.1(@swc/core@1.13.5)(esbuild@0.25.12)) + storybook: 10.3.0-alpha.0(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + ts-dedent: 2.2.0 + + '@storybook/builder-vite@10.3.0-alpha.0(esbuild@0.25.12)(msw@2.12.7(@types/node@24.10.1)(typescript@5.9.3))(rollup@4.52.5)(storybook@10.3.0-alpha.0(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(vite@7.2.2(@types/node@24.10.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.0))(webpack@5.102.1(@swc/core@1.13.5)(esbuild@0.25.12))': + dependencies: + '@storybook/csf-plugin': 10.3.0-alpha.0(esbuild@0.25.12)(rollup@4.52.5)(storybook@10.3.0-alpha.0(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(vite@7.2.2(@types/node@24.10.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.0))(webpack@5.102.1(@swc/core@1.13.5)(esbuild@0.25.12)) '@vitest/mocker': 3.2.4(msw@2.12.7(@types/node@24.10.1)(typescript@5.9.3))(vite@7.2.2(@types/node@24.10.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.0)) - storybook: 10.2.0-alpha.14(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + storybook: 10.3.0-alpha.0(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) ts-dedent: 2.2.0 vite: 7.2.2(@types/node@24.10.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.0) transitivePeerDependencies: @@ -7596,11 +7777,11 @@ snapshots: - rollup - webpack - '@storybook/builder-vite@10.2.0-alpha.14(esbuild@0.25.12)(msw@2.12.7(@types/node@24.10.1)(typescript@5.9.3))(rollup@4.52.5)(storybook@10.2.0-alpha.14(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(vite@7.2.2(@types/node@24.10.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.0))(webpack@5.102.1(@swc/core@1.13.5)(esbuild@0.25.12))': + '@storybook/builder-vite@10.3.0-alpha.0(esbuild@0.25.12)(msw@2.12.7(@types/node@24.10.1)(typescript@5.9.3))(rollup@4.52.5)(storybook@10.3.0-alpha.0(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(vite@7.2.2(@types/node@24.10.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.0))(webpack@5.102.1(@swc/core@1.13.5)(esbuild@0.25.12))': dependencies: - '@storybook/csf-plugin': 10.2.0-alpha.14(esbuild@0.25.12)(rollup@4.52.5)(storybook@10.2.0-alpha.14(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(vite@7.2.2(@types/node@24.10.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.0))(webpack@5.102.1(@swc/core@1.13.5)(esbuild@0.25.12)) + '@storybook/csf-plugin': 10.3.0-alpha.0(esbuild@0.25.12)(rollup@4.52.5)(storybook@10.3.0-alpha.0(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(vite@7.2.2(@types/node@24.10.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.0))(webpack@5.102.1(@swc/core@1.13.5)(esbuild@0.25.12)) '@vitest/mocker': 3.2.4(msw@2.12.7(@types/node@24.10.1)(typescript@5.9.3))(vite@7.2.2(@types/node@24.10.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.0)) - storybook: 10.2.0-alpha.14(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + storybook: 10.3.0-alpha.0(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) ts-dedent: 2.2.0 vite: 7.2.2(@types/node@24.10.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.0) transitivePeerDependencies: @@ -7609,9 +7790,9 @@ snapshots: - rollup - webpack - '@storybook/csf-plugin@10.2.0-alpha.14(esbuild@0.25.12)(rollup@4.52.5)(storybook@10.2.0-alpha.14(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(vite@7.2.2(@types/node@24.10.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.0))(webpack@5.102.1(@swc/core@1.13.5)(esbuild@0.25.12))': + '@storybook/csf-plugin@10.3.0-alpha.0(esbuild@0.25.12)(rollup@4.52.5)(storybook@10.3.0-alpha.0(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(vite@7.2.2(@types/node@24.10.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.0))(webpack@5.102.1(@swc/core@1.13.5)(esbuild@0.25.12))': dependencies: - storybook: 10.2.0-alpha.14(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + storybook: 10.3.0-alpha.0(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) unplugin: 2.3.10 optionalDependencies: esbuild: 0.25.12 @@ -7619,9 +7800,9 @@ snapshots: vite: 7.2.2(@types/node@24.10.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.0) webpack: 5.102.1(@swc/core@1.13.5)(esbuild@0.25.12) - '@storybook/csf-plugin@10.2.0-alpha.14(esbuild@0.25.12)(rollup@4.52.5)(storybook@10.2.0-alpha.14(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(vite@7.2.2(@types/node@24.10.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.0))(webpack@5.102.1(@swc/core@1.13.5)(esbuild@0.25.12))': + '@storybook/csf-plugin@10.3.0-alpha.0(esbuild@0.25.12)(rollup@4.52.5)(storybook@10.3.0-alpha.0(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(vite@7.2.2(@types/node@24.10.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.0))(webpack@5.102.1(@swc/core@1.13.5)(esbuild@0.25.12))': dependencies: - storybook: 10.2.0-alpha.14(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + storybook: 10.3.0-alpha.0(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) unplugin: 2.3.10 optionalDependencies: esbuild: 0.25.12 @@ -7641,37 +7822,37 @@ snapshots: react: 19.2.0 react-dom: 19.2.0(react@19.2.0) - '@storybook/react-dom-shim@10.2.0-alpha.14(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@10.2.0-alpha.14(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))': + '@storybook/react-dom-shim@10.3.0-alpha.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@10.3.0-alpha.0(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))': dependencies: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - storybook: 10.2.0-alpha.14(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + storybook: 10.3.0-alpha.0(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@storybook/react-dom-shim@10.2.0-alpha.14(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@10.2.0-alpha.14(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))': + '@storybook/react-dom-shim@10.3.0-alpha.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@10.3.0-alpha.0(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))': dependencies: react: 19.2.0 react-dom: 19.2.0(react@19.2.0) - storybook: 10.2.0-alpha.14(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + storybook: 10.3.0-alpha.0(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@storybook/react-dom-shim@10.2.0-alpha.14(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@10.2.0-alpha.14(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))': + '@storybook/react-dom-shim@10.3.0-alpha.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@10.3.0-alpha.0(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))': dependencies: react: 19.2.0 react-dom: 19.2.0(react@19.2.0) - storybook: 10.2.0-alpha.14(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + storybook: 10.3.0-alpha.0(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@storybook/react-vite@10.2.0-alpha.14(esbuild@0.25.12)(msw@2.12.7(@types/node@24.10.1)(typescript@5.9.3))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@4.52.5)(storybook@10.2.0-alpha.14(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.9.3)(vite@7.2.2(@types/node@24.10.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.0))(webpack@5.102.1(@swc/core@1.13.5)(esbuild@0.25.12))': + '@storybook/react-vite@10.3.0-alpha.0(esbuild@0.25.12)(msw@2.12.7(@types/node@24.10.1)(typescript@5.9.3))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@4.52.5)(storybook@10.3.0-alpha.0(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.9.3)(vite@7.2.2(@types/node@24.10.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.0))(webpack@5.102.1(@swc/core@1.13.5)(esbuild@0.25.12))': dependencies: '@joshwooding/vite-plugin-react-docgen-typescript': 0.6.3(typescript@5.9.3)(vite@7.2.2(@types/node@24.10.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.0)) '@rollup/pluginutils': 5.3.0(rollup@4.52.5) - '@storybook/builder-vite': 10.2.0-alpha.14(esbuild@0.25.12)(msw@2.12.7(@types/node@24.10.1)(typescript@5.9.3))(rollup@4.52.5)(storybook@10.2.0-alpha.14(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(vite@7.2.2(@types/node@24.10.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.0))(webpack@5.102.1(@swc/core@1.13.5)(esbuild@0.25.12)) - '@storybook/react': 10.2.0-alpha.14(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@10.2.0-alpha.14(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.9.3) + '@storybook/builder-vite': 10.3.0-alpha.0(esbuild@0.25.12)(msw@2.12.7(@types/node@24.10.1)(typescript@5.9.3))(rollup@4.52.5)(storybook@10.3.0-alpha.0(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(vite@7.2.2(@types/node@24.10.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.0))(webpack@5.102.1(@swc/core@1.13.5)(esbuild@0.25.12)) + '@storybook/react': 10.3.0-alpha.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@10.3.0-alpha.0(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.9.3) empathic: 2.0.0 magic-string: 0.30.21 react: 18.3.1 react-docgen: 8.0.2 react-dom: 18.3.1(react@18.3.1) resolve: 1.22.11 - storybook: 10.2.0-alpha.14(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + storybook: 10.3.0-alpha.0(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) tsconfig-paths: 4.2.0 vite: 7.2.2(@types/node@24.10.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.0) transitivePeerDependencies: @@ -7682,19 +7863,19 @@ snapshots: - typescript - webpack - '@storybook/react-vite@10.2.0-alpha.14(esbuild@0.25.12)(msw@2.12.7(@types/node@24.10.1)(typescript@5.9.3))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(rollup@4.52.5)(storybook@10.2.0-alpha.14(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(typescript@5.9.3)(vite@7.2.2(@types/node@24.10.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.0))(webpack@5.102.1(@swc/core@1.13.5)(esbuild@0.25.12))': + '@storybook/react-vite@10.3.0-alpha.0(esbuild@0.25.12)(msw@2.12.7(@types/node@24.10.1)(typescript@5.9.3))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(rollup@4.52.5)(storybook@10.3.0-alpha.0(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(typescript@5.9.3)(vite@7.2.2(@types/node@24.10.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.0))(webpack@5.102.1(@swc/core@1.13.5)(esbuild@0.25.12))': dependencies: '@joshwooding/vite-plugin-react-docgen-typescript': 0.6.3(typescript@5.9.3)(vite@7.2.2(@types/node@24.10.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.0)) '@rollup/pluginutils': 5.3.0(rollup@4.52.5) - '@storybook/builder-vite': 10.2.0-alpha.14(esbuild@0.25.12)(msw@2.12.7(@types/node@24.10.1)(typescript@5.9.3))(rollup@4.52.5)(storybook@10.2.0-alpha.14(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(vite@7.2.2(@types/node@24.10.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.0))(webpack@5.102.1(@swc/core@1.13.5)(esbuild@0.25.12)) - '@storybook/react': 10.2.0-alpha.14(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@10.2.0-alpha.14(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(typescript@5.9.3) + '@storybook/builder-vite': 10.3.0-alpha.0(esbuild@0.25.12)(msw@2.12.7(@types/node@24.10.1)(typescript@5.9.3))(rollup@4.52.5)(storybook@10.3.0-alpha.0(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(vite@7.2.2(@types/node@24.10.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.0))(webpack@5.102.1(@swc/core@1.13.5)(esbuild@0.25.12)) + '@storybook/react': 10.3.0-alpha.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@10.3.0-alpha.0(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(typescript@5.9.3) empathic: 2.0.0 magic-string: 0.30.21 react: 19.2.0 react-docgen: 8.0.2 react-dom: 19.2.0(react@19.2.0) resolve: 1.22.11 - storybook: 10.2.0-alpha.14(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + storybook: 10.3.0-alpha.0(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) tsconfig-paths: 4.2.0 vite: 7.2.2(@types/node@24.10.1)(jiti@2.6.1)(less@4.4.2)(terser@5.44.0) transitivePeerDependencies: @@ -7705,27 +7886,27 @@ snapshots: - typescript - webpack - '@storybook/react@10.2.0-alpha.14(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@10.2.0-alpha.14(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.9.3)': + '@storybook/react@10.3.0-alpha.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@10.3.0-alpha.0(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(typescript@5.9.3)': dependencies: '@storybook/global': 5.0.0 - '@storybook/react-dom-shim': 10.2.0-alpha.14(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@10.2.0-alpha.14(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)) + '@storybook/react-dom-shim': 10.3.0-alpha.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@10.3.0-alpha.0(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)) react: 18.3.1 react-docgen: 8.0.2 react-dom: 18.3.1(react@18.3.1) - storybook: 10.2.0-alpha.14(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + storybook: 10.3.0-alpha.0(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@storybook/react@10.2.0-alpha.14(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@10.2.0-alpha.14(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(typescript@5.9.3)': + '@storybook/react@10.3.0-alpha.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@10.3.0-alpha.0(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(typescript@5.9.3)': dependencies: '@storybook/global': 5.0.0 - '@storybook/react-dom-shim': 10.2.0-alpha.14(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@10.2.0-alpha.14(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)) + '@storybook/react-dom-shim': 10.3.0-alpha.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@10.3.0-alpha.0(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)) react: 19.2.0 react-docgen: 8.0.2 react-dom: 19.2.0(react@19.2.0) - storybook: 10.2.0-alpha.14(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + storybook: 10.3.0-alpha.0(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: @@ -7983,7 +8164,7 @@ snapshots: '@vitest/mocker': 4.0.6(msw@2.12.7(@types/node@20.19.0)(typescript@5.9.3))(vite@7.2.2(@types/node@20.19.0)(jiti@2.6.1)(less@4.4.2)(terser@5.44.0)) playwright: 1.56.1 tinyrainbow: 3.0.3 - vitest: 4.0.6(@types/node@20.19.0)(@vitest/browser-playwright@4.0.6)(jiti@2.6.1)(less@4.4.2)(msw@2.12.7(@types/node@20.19.0)(typescript@5.9.3))(terser@5.44.0) + vitest: 4.0.6(@types/node@20.19.0)(@vitest/browser-playwright@4.0.6)(jiti@2.6.1)(jsdom@27.4.0)(less@4.4.2)(msw@2.12.7(@types/node@20.19.0)(typescript@5.9.3))(terser@5.44.0) transitivePeerDependencies: - bufferutil - msw @@ -8000,7 +8181,7 @@ snapshots: pngjs: 7.0.0 sirv: 3.0.2 tinyrainbow: 3.0.3 - vitest: 4.0.6(@types/node@20.19.0)(@vitest/browser-playwright@4.0.6)(jiti@2.6.1)(less@4.4.2)(msw@2.12.7(@types/node@20.19.0)(typescript@5.9.3))(terser@5.44.0) + vitest: 4.0.6(@types/node@20.19.0)(@vitest/browser-playwright@4.0.6)(jiti@2.6.1)(jsdom@27.4.0)(less@4.4.2)(msw@2.12.7(@types/node@20.19.0)(typescript@5.9.3))(terser@5.44.0) ws: 8.18.3 transitivePeerDependencies: - bufferutil @@ -8022,7 +8203,7 @@ snapshots: magicast: 0.3.5 std-env: 3.10.0 tinyrainbow: 3.0.3 - vitest: 4.0.6(@types/node@20.19.0)(@vitest/browser-playwright@4.0.6)(jiti@2.6.1)(less@4.4.2)(msw@2.12.7(@types/node@20.19.0)(typescript@5.9.3))(terser@5.44.0) + vitest: 4.0.6(@types/node@20.19.0)(@vitest/browser-playwright@4.0.6)(jiti@2.6.1)(jsdom@27.4.0)(less@4.4.2)(msw@2.12.7(@types/node@20.19.0)(typescript@5.9.3))(terser@5.44.0) optionalDependencies: '@vitest/browser': 4.0.6(msw@2.12.7(@types/node@20.19.0)(typescript@5.9.3))(vite@7.2.2(@types/node@20.19.0)(jiti@2.6.1)(less@4.4.2)(terser@5.44.0))(vitest@4.0.6) transitivePeerDependencies: @@ -8216,6 +8397,9 @@ snapshots: acorn@8.15.0: {} + agent-base@7.1.4: + optional: true + ai-tokenizer@1.0.6: {} ajv-formats@2.1.1(ajv@8.17.1): @@ -8312,6 +8496,11 @@ snapshots: dependencies: is-windows: 1.0.2 + bidi-js@1.0.3: + dependencies: + require-from-string: 2.0.2 + optional: true + birpc@2.8.0: {} body-parser@2.2.0: @@ -8599,6 +8788,14 @@ snapshots: dependencies: css-tree: 2.2.1 + cssstyle@5.3.7: + dependencies: + '@asamuzakjp/css-color': 4.1.1 + '@csstools/css-syntax-patches-for-csstree': 1.0.25 + css-tree: 3.1.0 + lru-cache: 11.2.4 + optional: true + csstype@3.1.3: {} csstype@3.2.3: {} @@ -8607,6 +8804,12 @@ snapshots: data-uri-to-buffer@4.0.1: {} + data-urls@6.0.1: + dependencies: + whatwg-mimetype: 5.0.0 + whatwg-url: 15.1.0 + optional: true + dataloader@1.4.0: {} date-fns@2.30.0: @@ -8617,6 +8820,9 @@ snapshots: dependencies: ms: 2.1.3 + decimal.js@10.6.0: + optional: true + decode-named-character-reference@1.2.0: dependencies: character-entities: 2.0.2 @@ -8721,6 +8927,9 @@ snapshots: entities@4.5.0: {} + entities@6.0.1: + optional: true + envinfo@7.20.0: {} errno@0.1.8: @@ -9118,6 +9327,13 @@ snapshots: hookable@5.5.3: {} + html-encoding-sniffer@6.0.0: + dependencies: + '@exodus/bytes': 1.9.0 + transitivePeerDependencies: + - '@noble/hashes' + optional: true + html-escaper@2.0.2: {} http-errors@2.0.0: @@ -9128,6 +9344,22 @@ snapshots: statuses: 2.0.1 toidentifier: 1.0.1 + http-proxy-agent@7.0.2: + dependencies: + agent-base: 7.1.4 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + optional: true + + https-proxy-agent@7.0.6: + dependencies: + agent-base: 7.1.4 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + optional: true + human-id@4.1.2: {} iconv-lite@0.6.3: @@ -9190,6 +9422,9 @@ snapshots: is-number@7.0.0: {} + is-potential-custom-element-name@1.0.1: + optional: true + is-promise@4.0.0: {} is-subdir@1.2.0: @@ -9257,6 +9492,35 @@ snapshots: dependencies: argparse: 2.0.1 + jsdom@27.4.0: + dependencies: + '@acemir/cssom': 0.9.31 + '@asamuzakjp/dom-selector': 6.7.6 + '@exodus/bytes': 1.9.0 + cssstyle: 5.3.7 + data-urls: 6.0.1 + decimal.js: 10.6.0 + html-encoding-sniffer: 6.0.0 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6 + is-potential-custom-element-name: 1.0.1 + parse5: 8.0.0 + saxes: 6.0.0 + symbol-tree: 3.2.4 + tough-cookie: 6.0.0 + w3c-xmlserializer: 5.0.0 + webidl-conversions: 8.0.1 + whatwg-mimetype: 4.0.0 + whatwg-url: 15.1.0 + ws: 8.18.3 + xml-name-validator: 5.0.0 + transitivePeerDependencies: + - '@noble/hashes' + - bufferutil + - supports-color + - utf-8-validate + optional: true + jsesc@3.1.0: {} json-buffer@3.0.1: {} @@ -9646,6 +9910,11 @@ snapshots: parse-node-version@1.0.1: optional: true + parse5@8.0.0: + dependencies: + entities: 6.0.1 + optional: true + parseurl@1.3.3: {} path-exists@4.0.0: {} @@ -9680,6 +9949,8 @@ snapshots: picomatch@4.0.3: {} + picoquery@2.5.0: {} + pify@4.0.1: {} pixelmatch@7.1.0: @@ -10352,6 +10623,11 @@ snapshots: sax@1.4.3: {} + saxes@6.0.0: + dependencies: + xmlchars: 2.2.0 + optional: true + scheduler@0.23.2: dependencies: loose-envify: 1.4.0 @@ -10510,11 +10786,11 @@ snapshots: std-env@3.10.0: {} - storybook-addon-test-codegen@3.0.0(storybook@10.2.0-alpha.14(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)): + storybook-addon-test-codegen@3.0.0(storybook@10.3.0-alpha.0(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)): dependencies: - storybook: 10.2.0-alpha.14(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + storybook: 10.3.0-alpha.0(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - storybook@10.2.0-alpha.14(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + storybook@10.3.0-alpha.0(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: '@storybook/global': 5.0.0 '@storybook/icons': 2.0.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -10537,7 +10813,7 @@ snapshots: - react-dom - utf-8-validate - storybook@10.2.0-alpha.14(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0): + storybook@10.3.0-alpha.0(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0): dependencies: '@storybook/global': 5.0.0 '@storybook/icons': 2.0.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) @@ -10621,6 +10897,9 @@ snapshots: picocolors: 1.1.1 sax: 1.4.3 + symbol-tree@3.2.4: + optional: true + tagged-tag@1.0.0: optional: true @@ -10705,6 +10984,11 @@ snapshots: tr46@0.0.3: {} + tr46@6.0.0: + dependencies: + punycode: 2.3.1 + optional: true + tree-kill@1.2.2: {} ts-dedent@2.2.0: {} @@ -10965,7 +11249,7 @@ snapshots: less: 4.4.2 terser: 5.44.0 - vitest@4.0.6(@types/node@20.19.0)(@vitest/browser-playwright@4.0.6)(jiti@2.6.1)(less@4.4.2)(msw@2.12.7(@types/node@20.19.0)(typescript@5.9.3))(terser@5.44.0): + vitest@4.0.6(@types/node@20.19.0)(@vitest/browser-playwright@4.0.6)(jiti@2.6.1)(jsdom@27.4.0)(less@4.4.2)(msw@2.12.7(@types/node@20.19.0)(typescript@5.9.3))(terser@5.44.0): dependencies: '@vitest/expect': 4.0.6 '@vitest/mocker': 4.0.6(msw@2.12.7(@types/node@20.19.0)(typescript@5.9.3))(vite@7.2.2(@types/node@20.19.0)(jiti@2.6.1)(less@4.4.2)(terser@5.44.0)) @@ -10990,6 +11274,7 @@ snapshots: optionalDependencies: '@types/node': 20.19.0 '@vitest/browser-playwright': 4.0.6(msw@2.12.7(@types/node@20.19.0)(typescript@5.9.3))(playwright@1.56.1)(vite@7.2.2(@types/node@20.19.0)(jiti@2.6.1)(less@4.4.2)(terser@5.44.0))(vitest@4.0.6) + jsdom: 27.4.0 transitivePeerDependencies: - jiti - less @@ -11004,6 +11289,11 @@ snapshots: - tsx - yaml + w3c-xmlserializer@5.0.0: + dependencies: + xml-name-validator: 5.0.0 + optional: true + watchpack@2.4.4: dependencies: glob-to-regexp: 0.4.1 @@ -11014,6 +11304,9 @@ snapshots: webidl-conversions@3.0.1: {} + webidl-conversions@8.0.1: + optional: true + webpack-sources@3.3.3: optional: true @@ -11052,6 +11345,18 @@ snapshots: - uglify-js optional: true + whatwg-mimetype@4.0.0: + optional: true + + whatwg-mimetype@5.0.0: + optional: true + + whatwg-url@15.1.0: + dependencies: + tr46: 6.0.0 + webidl-conversions: 8.0.1 + optional: true + whatwg-url@5.0.0: dependencies: tr46: 0.0.3 @@ -11095,6 +11400,12 @@ snapshots: dependencies: is-wsl: 3.1.0 + xml-name-validator@5.0.0: + optional: true + + xmlchars@2.2.0: + optional: true + y18n@5.0.8: {} yallist@3.1.1: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 5b3a1b09..e92d4d2b 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -6,15 +6,15 @@ packages: - eval/evals/*/experiments/*/project catalog: - '@storybook/addon-a11y': 10.2.0-alpha.14 - '@storybook/addon-docs': 10.2.0-alpha.14 - '@storybook/addon-vitest': 10.2.0-alpha.14 - '@storybook/react-vite': 10.2.0-alpha.14 + '@storybook/addon-a11y': 10.3.0-alpha.0 + '@storybook/addon-docs': 10.3.0-alpha.0 + '@storybook/addon-vitest': 10.3.0-alpha.0 + '@storybook/react-vite': 10.3.0-alpha.0 '@tmcp/adapter-valibot': ^0.1.4 '@tmcp/transport-http': ^0.8.0 '@tmcp/transport-stdio': ^0.4.1 - eslint-plugin-storybook: 10.2.0-alpha.14 - storybook: 10.2.0-alpha.14 + eslint-plugin-storybook: 10.3.0-alpha.0 + storybook: 10.3.0-alpha.0 tmcp: ^1.16.0 tsdown: ^0.15.12 typescript: ^5.9.3 @@ -25,10 +25,10 @@ catalog: catalogs: experiments: '@eslint/js': 9.39.1 - '@storybook/addon-a11y': 10.2.0-alpha.14 - '@storybook/addon-docs': 10.2.0-alpha.14 - '@storybook/addon-vitest': 10.2.0-alpha.14 - '@storybook/react-vite': 10.2.0-alpha.14 + '@storybook/addon-a11y': 10.3.0-alpha.0 + '@storybook/addon-docs': 10.3.0-alpha.0 + '@storybook/addon-vitest': 10.3.0-alpha.0 + '@storybook/react-vite': 10.3.0-alpha.0 '@types/node': 24.10.1 '@types/react': 19.2.6 '@types/react-dom': 19.2.3 @@ -37,11 +37,11 @@ catalogs: eslint: 9.39.1 eslint-plugin-react-hooks: 7.0.1 eslint-plugin-react-refresh: 0.4.24 - eslint-plugin-storybook: 10.2.0-alpha.14 + eslint-plugin-storybook: 10.3.0-alpha.0 globals: 16.5.0 react: 19.2.0 react-dom: 19.2.0 - storybook: 10.2.0-alpha.14 + storybook: 10.3.0-alpha.0 typescript: 5.9.3 typescript-eslint: 8.47.0 vite: 7.2.2 diff --git a/turbo.json b/turbo.json index f6f6fc27..7e7bde26 100644 --- a/turbo.json +++ b/turbo.json @@ -22,6 +22,7 @@ }, "storybook": { "dependsOn": ["^build"], + "cache": false, "persistent": true, "interruptible": true },